AL+

Language: RO (română) EN (English)

Email us: paul@alplustech.com

Looking back at the week of 2–8 April 2025

Treat Wasm bindings as a versioned binary contract

Rust’s Wasm C ABI correction shows why generated bindings and modules must travel together. Plan compatibility checks around the actual compiler release.

Citiți articolul în română

Generated bindings belong to the binary contract of a Wasm module. When a compiler changes how values cross that boundary, keeping the source function unchanged does not establish compatibility. Ship and retain the module together with the glue that knows how to call it, and make that pairing part of the release record.

Looking back from November 2026, Rust’s 4 April 2025 notice announced an upcoming correction to the C ABI for wasm32-unknown-unknown. It was not an announcement that the correction had already shipped on stable. The Rust 1.89.0 release on 7 August 2025 subsequently confirmed the standards-compliant ABI. A migration account needs both dates.

Source layout does not settle a call boundary

An application binary interface describes how arguments and results are represented when code calls other code. A shared understanding of a structure’s fields is only part of that agreement. The caller and callee also need to agree whether the structure travels through separate values or through memory.

The April notice illustrates this distinction with a structure containing two integer fields. Rust’s legacy convention split that argument into two Wasm arguments; the standard C convention passed it indirectly through linear memory. The source-level operation could still be addition in both cases, while the host needed a different calling sequence.

That is why a repr(C) declaration cannot, by itself, prove that handwritten JavaScript glue is correct. Memory layout and function signature lowering are separate parts of the boundary. An integration that hardcodes the older call shape can fail even when the Rust source and the intended arithmetic look unchanged to a reviewer.

This article concerns that compiler and generated-binding boundary. It does not compare Wasm runtimes, prescribe a plugin capability model or assess whether a small compiler is suitable for production. Those are different decisions with different evidence requirements.

Warnings were preparation, not the switch

The future-compatibility warning change was merged on 26 March 2025. Its job was to identify affected calls and definitions before the transition. A warning landing in the compiler repository is evidence of preparation; it is not proof that a stable compiler has adopted the new ABI.

The April post described migration testing with a suitable nightly compiler and the specification mode. That was advice for the transition as it stood then. For a November 2026 maintenance task, begin with the compiler actually used by the product and its release behavior. Repeating historical nightly instructions without checking their context would turn useful evidence into stale operational guidance.

The same distinction applies to generated bindings. The post reports that wasm-bindgen had already changed its generation approach in late 2023. That does not establish the version used by an arbitrary application. A transitive dependency or retained generated file may still embody older assumptions. Inspect the resolved toolchain and generated artifacts rather than relying on a library name.

The release unit includes the caller

Consider an illustrative web application that serves a Wasm file and a generated JavaScript wrapper. Rebuilding the Wasm file alone could leave an old wrapper calling a new interface. Rebuilding both but allowing independent caching could still deliver mismatched files. These are compatibility scenarios, not reported failures observed in a deployed product.

A proposed release record should identify the compiler, binding generator and the two resulting artifacts. Use a delivery arrangement that keeps the wrapper associated with the module it was generated to call. Content-addressed filenames can help identify that association, but the application still needs to load the matching pair and retain any pair required for rollback.

An acceptance check should exercise the public boundary through the actual wrapper. Successful Rust compilation checks only one side. Module instantiation alone may also miss a mismatch that appears when an affected export is called. Choose representative calls that cross the changed signature shape and check their results against the agreed contract.

For a manually maintained host interface, document memory ownership and lifetimes alongside argument representation. Replacing a by-value structure with a pointer can move work into the caller, including arranging memory and keeping it valid for the call. That change needs an integration design; it should not be presented as a harmless textual substitution.

Pinning can buy time

The strongest counterargument is operational: an existing product may have a known working compiler and generated pair, with no immediate reason to rebuild it. Pinning the compiler can postpone the transition and avoid mixing incompatible assumptions during an unrelated release. The April notice itself identified pinning as one possible temporary response.

The cost is deferred migration. Pinning does not make the old interface standard, and a future toolchain upgrade still needs an owner. Keep the reason for the pin, the affected exports and the condition for removing it. Avoid presenting an indefinite frozen compiler as a completed compatibility strategy.

The scope is also narrow. The notice concerns extern "C" on wasm32-unknown-unknown; it does not say every Rust target or every Rust Wasm application changed in the same way. An application that does not cross the affected boundary should not inherit migration work merely because it uses WebAssembly.

For custom software development, ask for evidence that the delivered caller and module agree, plus a recoverable pair for rollback. No compilation or compatibility experiment was performed for this article. The historical correction supplies the reason to check; the product’s own artifacts must supply the proof that its next release still works.