Repository navigation
Conversation
… macros Embedders currently lack a mechanism to track host-side heap memory occupied by component model resources (bytecodealliance#12984). Following the prior art of Servo's `heapsize` and Firefox's `malloc_size_of`, this commit introduces two foundational traits: - `HostHeapUsage`: reports dynamically allocated heap bytes owned by descendants (`heap_size_of_children`). - `FixedHostHeapUsage: HostHeapUsage + Sized`: marker subtrait for types whose heap footprint is constant under mutation (scalars, fixed structures, OS handles). A blanket impl automatically implements `HostHeapUsage` returning 0. Two procedural derive macros are provided in `wasmtime-component-macro` and re-exported from `wasmtime::component`: - `#[derive(HostHeapUsage)]`: recursively sums `heap_size_of_children` across all fields. - `#[derive(FixedHostHeapUsage)]`: asserts at compile time that all fields are fixed-size (via `FixedHostHeapField`, including `Option`, `Result`, arrays, and tuples of fixed-size types), preventing accidental additions of unmetered buffers. The proc macros are added in order to provide a safer and more convenient route for embedders and in-tree implementations to target the required traits. Notably, the ability to derive the traits is only possible if members of the struct/enum already implement the required trait. Attempting to, for instance, derive the HostHeapUsage on struct containing a type which we don't know how to track (e.g. An Arc<T>) will generate a compile-time failure hinting that the embedder must implement the trait manually with more careful consideration.
Embedders currently lack an aggregate host-side memory boundary for component model resources (bytecodealliance#12984). Existing mitigations from PR bytecodealliance#12652 (entry counts and hostcall fuel) bound handle quantities and transfer sizes, but do not bound cumulative host heap allocation across resources. This commit integrates the `HostHeapUsage` trait into `ResourceTable`. The `FixedHostHeapUsage` denotes that a type has fixed size (or is untracked) and cannot be mutated internally in a way that would change its metered host heap usage. With that, these types may be accessed via `get_mut` in the style prevelant already. Types only implementing `HostHeapUsage` that aren't fixed must have their mutations be made fallible, so those mutations go through `update` instead which provides mutable access within an enclosure, potentially raising an error if the mutations result in exceeding the heap limit in place. All required callsites in tree have been updated to use these new, required traits. There are limits and in some cases there are limited untracked heap allocations that are considered to be safe or which are amortized in a way that would make accounting using this mechanism not possible.
posborne
requested review from
alexcrichton and
rvolosatovs
and removed request for
a team
October 30, 2026 22:19
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Embedders currently lack an aggregate host-side memory boundary for component model resources in
ResourceTable. While #12652 added mitigations around handle counts and hostcall fuel, cumulative host heap allocations owned by resources inResourceTablewere previously untracked by any umbrella mechanism.Over the past several releases, Wasmtime has had to address a recurring class of guest-driven host memory exhaustion advisories with mitigations including GHSA-852m-cvvp-9p4w and GHSA-243v-98vx-264h (#12652), GHSA-c9gc-w9vx-w86p, GHSA-gqmc-89g8-p25r, and GHSA-6fr9-xmw9-5352. While per-resource and per-call limits help, they do not bound the aggregate host heap memory accumulated across entries in a
ResourceTable.Solution
This PR adds host heap usage accounting and optional per-table byte limits to
wasmtime::component::ResourceTable. This provides a level of umbrella coverage to protect against host paths that may not have protections currently and to provide a higher level limit that is easier to reason about for embedders.The way that this is achieved involves the introduction of a
HostHeapUsagetrait which is required for all resources. This is accompanied by aFixedHostHeapUsagetrait as a marker for types which do not contain children with heap storage not accounted for in their own size directly. Methods on the table that push, delete or mutate (update) resources use the traits to account for the heap usage changes associated with the operation. If a limit is set and an operation causes the heap usage to grow beyond the set limit, the operations return an error which will typically result in a guest-side trap.These new requirements necessitate updates across the wasmtime tree and will be a breaking change for embedders that are pushing their own resources into
ResourceTables.Design Decisions
The code here has gone through a few iterations and updates based on discussion in #12984. What is present here tries to incorporate that feedback and is closer to some of the implementation from servo/firefox/stylo
MallocSizeOftrait.In instrumenting the code to implement the traits, I decided that to ease the burden on embedders and to provide some additional static guarantees, it would be beneficial to introduce proc-macros in order to aid in deriving the traits on compatible structs and enums.
For mutation I went with a closure-based
updaterather than a guard, because the limit check has to be fallible and a guard could only account inDrop. This makes former get_mut call sites a bit noisier. Since update can only measure after the mutation runs, growth past the limit is reported rather than prevented, and the mutation isn't rolled back because the error is expected to trap. The overshoot is roughly limited to what a single host call can allocate.Across the code in tree (mostly wasi p2/p3), I tried to provide pragmatic implementations of the trait where reasonable and erred on the side of overcounting bytes in most cases. There are some reference counted cases which are not tracked with complete accuracy but, even in those cases, abuse should be challenging as the fixed size of the resource will be counted even if the amortized cost of the shared data is left unaccounted.
Future Work
The changes here are sprawling, so I wanted to avoid increasing the scope beyond what was required for purpose and reasonable ergonomics (adding derive). Potential future work that I opted to not try to incorporate here include:
ResourceLimiter.Closes #12984