You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When the --weak-refs feature is enabled, the JS shim code that wasmbindgen-cli generates (out_dir/libname_bg.js file) is incorrect and leads to UAFs (e.g., double free) when a decorated [wasm_bindgen] method uses a by-value receiver.
The very short technical description of the bug is that in the JS glue wrapping such a method is missing a call to ThatClassFinalization.unregister(this);.
Now, somewhere within JS code interacting with this wasm library, do:
letfoo=newFoo();letfoo2=foo.identity();
Expected behavior
Everything is fine
Actual behavior
Some use-after-free or double-free error occurs, such as a borrow_mut() error, once garbage collection disposes of both foo and foo2.
Screenshot of a debugged situation
The following is not exactly a screenshot of the minimal repro, but rather, of a personal debugging session that was conducted to identify the cause of the borrow_mut error. In that debugging session, all WasmRefCells were monkey-patched to log whenever a borrow occurred or one ended, with a global ever incrementing "uid" to distinguish between each WasmRefCell instance:
As you can see, we have a wbg_…_free called twice on the same instance #4.
Explanation
When foo is GC-ed, wasm.__wbg_foo_free(ptr) will be called by the Finalization registry, but that ptr was actually given in an owned fashion to wasm.foo_identity(ptr), which deallocates that ptr when it does Box::from_raw:
Code for wasm.foo_identity
/// `wasm.foo_identity`pubextern"C"fn__wasm_bindgen_generated_Foo_identity(me:u32,) -> <Fooas wasm_bindgen::convert::ReturnWasmAbi>::Abi{let _ret = {// let me = unsafe { *Box::from_raw(me) }; /* frees `me` */let me = unsafe{ <Fooas wasm_bindgen::convert::FromWasmAbi>::from_abi(me)};
me.identity()};
<Fooas wasm_bindgen::convert::ReturnWasmAbi>::return_abi(_ret)}
Solution
Do the same thing that the glue for JS free currently does (in that regard, free() is not that special, it could simply be the glue generated for a dummy drop-ping method, such as impl Foo { pub fn free (self) {} }.
Describe the Bug
When the
--weak-refs
feature is enabled, the JS shim code thatwasmbindgen-cli
generates (out_dir/libname_bg.js
file) is incorrect and leads to UAFs (e.g., double free) when a decorated[wasm_bindgen]
method uses a by-value receiver.The very short technical description of the bug is that in the JS glue wrapping such a method is missing a call to
ThatClassFinalization.unregister(this);
.Steps to Reproduce
The generated
out_dir/example_bg.js
will then contain, among other things:Now, somewhere within JS code interacting with this wasm library, do:
Expected behavior
Everything is fine
Actual behavior
Some use-after-free or double-free error occurs, such as a
borrow_mut()
error, once garbage collection disposes of bothfoo
andfoo2
.Screenshot of a debugged situation
The following is not exactly a screenshot of the minimal repro, but rather, of a personal debugging session that was conducted to identify the cause of the
borrow_mut
error. In that debugging session, allWasmRefCell
s were monkey-patched to log whenever a borrow occurred or one ended, with a global ever incrementing "uid" to distinguish between eachWasmRefCell
instance:As you can see, we have a
wbg_…_free
called twice on the same instance#4
.Explanation
When
foo
is GC-ed,wasm.__wbg_foo_free(ptr)
will be called by theFinalization
registry, but thatptr
was actually given in an owned fashion towasm.foo_identity(ptr)
, which deallocates thatptr
when it doesBox::from_raw
:Code for
wasm.foo_identity
Solution
Do the same thing that the glue for JS
free
currently does (in that regard,free()
is not that special, it could simply be the glue generated for a dummydrop
-ping method, such asimpl Foo { pub fn free (self) {} }
.Fix implemented in #2448
The text was updated successfully, but these errors were encountered: