Skip to content

feat(vm): limit globals per contract#16047

Open
jakmeier wants to merge 5 commits into
near:masterfrom
jakmeier:globals_per_contract_cap
Open

feat(vm): limit globals per contract#16047
jakmeier wants to merge 5 commits into
near:masterfrom
jakmeier:globals_per_contract_cap

Conversation

@jakmeier

Copy link
Copy Markdown
Contributor

The VM currently has not explicit limit on declared Wasm globals in a contract. However, MAX_CORE_INSTANCE_SIZE = 1MiB acts as an implicit limit today.

This PR sets the limit to 100k globally, which would add 1.6MB to the core instance size, thus it is less restrictive than the existing limit.

A follow-up PR will make this limit stricter and combine it with other limits that contribute to MAX_CORE_INSTANCE_SIZE. But the goal is to introduce each limit in a separate PR before combining them.

The VM currently has not explicit limit on declared Wasm globals in a contract.
However, `MAX_CORE_INSTANCE_SIZE = 1MiB` acts as an implicit limit today.

This PR sets the limit to 100k globally, which would add 1.6MB to the core
instance size, thus it is less restrictive than the existing limit.

A follow-up PR will make this limit stricter and combine it with other limits
that contribute to MAX_CORE_INSTANCE_SIZE. But the goal is to introduce
each limit in a separate PR before combining them.
@jakmeier

Copy link
Copy Markdown
Contributor Author

Fyi, next, I have one more commit ready that adds an explicit limit for the number of escaped functions.

After that, all limits are in place to capture all errors in the prepare phase rather than in the loading phase.

@jakmeier
jakmeier requested a review from ssavenko-near July 10, 2026 13:57
@jakmeier
jakmeier marked this pull request as ready for review July 10, 2026 13:57
@jakmeier
jakmeier requested review from a team and frol as code owners July 10, 2026 13:57
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.95238% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.21%. Comparing base (b8a041c) to head (9d79a0b).

Files with missing lines Patch % Lines
runtime/near-vm-runner/src/prepare.rs 84.61% 0 Missing and 2 partials ⚠️
runtime/near-vm-runner/src/logic/errors.rs 0.00% 1 Missing ⚠️
runtime/runtime/src/conversions.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #16047      +/-   ##
==========================================
+ Coverage   73.19%   73.21%   +0.01%     
==========================================
  Files         856      856              
  Lines      188394   188415      +21     
  Branches   188394   188415      +21     
==========================================
+ Hits       137904   137943      +39     
+ Misses      46070    46049      -21     
- Partials     4420     4423       +3     
Flag Coverage Δ
pytests-nightly 1.22% <0.00%> (-0.01%) ⬇️
unittests 69.84% <80.95%> (-0.02%) ⬇️
unittests-nightly 69.86% <80.95%> (+<0.01%) ⬆️
unittests-spice 65.46% <80.95%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ssavenko-near ssavenko-near left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So what is the issue with letting the loading fail?

I am still not convinced by the value of repeating the internal compiler limits just to avoid it failing in the load phase. We should still be prepared for loading to fail, there's no contract/promise that the phase succeeds TBMK. We probably do not want to keep these limits in sync with upstream, introduce new ones, remove outdated, adjust the values, etc...

@jakmeier

Copy link
Copy Markdown
Contributor Author

So what is the issue with letting the loading fail?

I am still not convinced by the value of repeating the internal compiler limits just to avoid it failing in the load phase. We should still be prepared for loading to fail, there's no contract/promise that the phase succeeds TBMK. We probably do not want to keep these limits in sync with upstream, introduce new ones, remove outdated, adjust the values, etc...

Hm, so before we switched to Wasmtime, there were no loading errors. But I guess you are right to challenge the assumption that we need to preserve that.

But I think it is actually less about when we surface the error (preparation vs loading) and more about controlling what is accepted as valid code. I expect we will regularly update Wasmtime and if that includes loading errors we don't control, it may cut us in two ways.

  1. A more restrictive limit in upstream may break mainnet smart contracts.
  2. A more lenient limit may be a resource exhaustion problem for us, potentially a security critical.

By maintaining explicit limits in our code base, together with some tests that check they are in line with Wasmtime's limit, we can be sure we don't accidentally pull in such changes.

My more general opinion is that we actually need to keep understanding compiler internals, whether we make it explicit in our code or not. Near offers what I call a "remote compilation service" and hence Near engineers should be deeply familiar with this compilation process.

But I'm curious to hear other opinions, @ssavenko-near, @darioush WDYT?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants