-
Notifications
You must be signed in to change notification settings - Fork 361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: convert result of allocate_mappings from signed to unsigned #473
Conversation
Having a way to reproduce would be super helpful, even if this include setting up some other project. |
I think that in order to reproduce this, you need to create enough SourceMapConsumers that the WASM memory exceeds 2GB. I'll see if I can write a test. |
ah, rebuilt mappings.wasm with -g and it looks like the
|
figured it out, my test for "are we over 2GB yet" was wrong, and the "unreachable" was happening when the 4GB limit was reached. the test is updated now to check the size of the WASM memory exceeds 3GB. Experimentally, exceeding 2GB wasn't enough because the mappings weren't being allocated past the 2GB byte mark. The test as written now fails without the fix, and passes with the fix. |
Thanks a ton for being able to have a test for this! Now, I'm wondering about the actual fix. Your test highlights that the returned value starts being negative from the Javascript codebase around 2GB (i.e. 2 * 1024 * 1024 * 1024). I'm wondering if using unsigned right shift is actually correct. It sounds like we may just map to some arbitrary address, that is no longer negative, so it no longer throw. But it may not necessarily be the address we meant. |
It’s because the return type of allocate_mappings is i32 in the compiled
wasm, which is a *signed* 32 bit integer, i.e. 31 bits of int plus one bit
saying whether the number is positive or negative. 2 GB is the largest
positive integer that can be represented in an i32, so once it gets above
that it wraps around to negative. The right shift “reinterprets” the number
as *unsigned*, which is what the original rust type was (you can’t have a
negative pointer).
On Tue, Nov 22, 2022 at 06:55 ochameau ***@***.***> wrote:
Thanks a ton for being able to have a test for this!
Now, I'm wondering about the actual fix.
I'm new to Rust and Wasm so I don't know exactly what is going on.
It looks like once we reach some particular memory size, the address
returned by rust's allocate_mapping function gets out of hands. This is
typed as *mut u8. This isn't clear what it means from the Javascript
point of view...
Your test highlights that the returned value starts being negative from
the Javascript codebase around 2GB (i.e. 2 * 1024 * 1024 * 1024).
Why would that suddently happen? Is there really a 2GB limit for Wasm
memory? If so why exports.memory.buffer.byteLength is able to go above
this limit?
Also Javascript numbers support larger numbers. Why does that start being
negative when going over 2GB? Could there be a typedef issue in rust code?
Or is there something wrong in the convertion of *mut u8 to JS value?
I'm wondering if using unsigned right shift is actually correct. It sounds
like we may just map to some arbitrary address, that is no longer negative,
so it no longer throw. But it may not necessarily be the address we meant.
—
Reply to this email directly, view it on GitHub
<#473 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABKGACY3JHKKO7H26HJRWTWJTNE3ANCNFSM6AAAAAASC4IKHE>
.
You are receiving this because you authored the thread.Message ID:
***@***.***>
--
j
|
Ah, I think CI might be hitting "unreachable" because possibly the runner has less RAM, so V8 chooses a smaller heap limit...? |
Thanks a lot for the explanation. It makes sense. I'm really surprised there isn't any intermediate layer to do that automatically. There is still one suspicous behavior. This may be unrelated but may highlight some other leak. You can see that with the following patch:
Why is there such an increase in memory and then we are able to allocate back in lower addresses? Anyway, feel free to ignore. I think your patch is super valuable as-is. |
@ochameau i think that's because the memory gets freed when the SourceMapConsumer is destroyed. Once the memory is freed, the allocator can use the lower addresses again. |
BTW, we don't need to also do this for _mappingsPtr. It's fine for that one to be negative because we only ever use it to pass it back into wasm, which will correctly interpret the value as unsigned. We need it for mappingsBufPtr because we use it to index into a Uint8Array, i.e. the WASM memory object. Agree that converting to wasm-bindgen would be a good idea! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay, I missed the notification about your newest revision...
Thanks a lot for having looked into this!
fix: convert result of allocate_mappings from signed to unsigned (mozilla#473)
I haven't yet tested this because I don't have a good repro locally, but this might fix #412? I noticed that the rust bundle returns a signed integer, and I'm seeing it sometimes come back as negative (i.e. > 2GB). I think this maybe started being an issue with https://v8.dev/blog/4gb-wasm-memory.