-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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: Crash during PThread initialization on big-endian machine #23700
base: main
Are you sure you want to change the base?
fix: Crash during PThread initialization on big-endian machine #23700
Conversation
2dae9cd
to
13d97b3
Compare
src/runtime_shared.js
Outdated
var h16 = new Int16Array(1); | ||
var h8 = new Int8Array(h16.buffer); | ||
h16[0] = 42; | ||
return h8[0] === 42 && h8[1] === 0; // little endian ordering |
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.
Surely we must already have helpers that perform this kind of thing in emscripten? Since all the non-atomic read/writes already work?
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.
Other accesses use the DataView methods.
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.
Similar test is performed in the runtime_debug.js, but it is only included with ASSERTIONS option.
The general mechanism we use for this is emscripten/tools/acorn-optimizer.mjs Lines 1103 to 1105 in bb7fd25
Perhaps the best thing is to update that pass so it handles Atomic operations? |
|
I agree, yes, that is necessary. I am just saying that doing it in the processing pass has advantages. Specifically it will find all atomic operations, guaranteeing that we don't forget any (as you wrote above, "There are other places using Atomic.something that likely have the same issue").
Oh, definitely, yes, we want to use wrapper functions. The processing pass should just add calls to those wrappers. That is what it does today: it replaces e.g.
And
I am suggesting that Atomics be implemented in a similar way. |
76f6d46
to
6d93671
Compare
src/runtime_shared.js
Outdated
} | ||
|
||
#if SUPPORT_BIG_ENDIAN | ||
var nativeByteOrder = (() => { |
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.
I think this can live in liblittle_endian_heap.js
too as a library function.
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.
I'll try to move as much as possible.
HEAPU32.unsigned = (x => x >>> 0); | ||
#if WASM_BIGINT | ||
HEAPU64.unsigned = (x => x >= 0 ? x : BigInt(2**64) + x); | ||
#endif |
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.
Ideally we could avoid adding this here and keep all the code chagnes to liblittle_endian_heap.js.
Ideally we could also avoid adding extra methods to these heaps, but maybe thats not easy.
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.
I didn't really find a better way to keep the extra methods out while not introducing per-type functions (and associated transformations).
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.
Can you just use the uppercase version here? i.e. why do we need the new lower case versions?
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.
I wonder if wen also move these lines to liblittle_endian_heap.js?
Perhaps they could be part of the __postset
too?
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.
re the new variables - if the uppercased variables are used they get replaced by e.g. the growable heap wrappers.
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.
One option would be to rename updateMemoryViews
to _updateMemoryViews
. Assign _updateMemoryViews
to updateMemoryViews
and use to __postset
to override the new updateMemoryViews
variable.
If you prefer this option, I can look into that on Monday.
'$LE_ATOMICS_SUB', | ||
'$LE_ATOMICS_WAIT', | ||
'$LE_ATOMICS_WAITASYNC', | ||
'$LE_ATOMICS_XOR', |
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.
While I agree it would be good to add all of these, I also thing we might want to only add the ones that we actually use (and also test).
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.
I thought that the whole point of this approach was to actually implement comprehensive support like was done to the non-atomic memory accesses done from JS code.
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.
Yes, I suppose you right, seems reasonable to leave them all in then.
But lets skip 64-bit atomics and just fail in that case, to keep things simple. I don't think anyone should be doing that.
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.
I've tested it on the following program:
#include <atomic>
#include <print>
#include <emscripten.h>
int main(){
std::atomic<unsigned long long> x = 0x0123456789ABCDEF;
std::println("x: {:X}", x.load());
EM_ASM({ Atomics.compareExchange(HEAP64, ($0)/8, BigInt("0x0123456789ABCDEF"), BigInt("0xFEDCBA9876543210")); }, &x);
std::println("x: {:X}", x.load());
}
built with
em++ -o main.js -s USE_PTHREADS=1 -s PROXY_TO_PTHREAD=1 -s PTHREAD_POOL_SIZE=8 -s SUPPORT_BIG_ENDIAN=1 -pthread -s EXIT_RUNTIME=1 -s ALLOW_MEMORY_GROWTH=1 -std=c++23 main.cpp
And I do get the expected result on both LE and BE:
x: 123456789ABCDEF
x: FEDCBA9876543210
src/runtime_shared.js
Outdated
else | ||
return res - BigInt(2**64); | ||
} | ||
), |
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.
Do we need to support more than 4 byte access? Maybe lets just skip then completely? If anyone tries to do an atomic 64-bit access they would see a crash accessing nativeByteOrder OOB.
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.
See the post above... I think that the 8B atomics will be needed eventually for the MEMORY64.
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.
I dont think we want to be adding complexity to support APIs that we don't use in emscripten.
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.
That was just an example, perhaps more realistic would be just accessing 8B atomic or perhaps 2x4B pointer+counter pair value.
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.
Sure, but until we get a request that somebody wants to to actually do that from JS then I don't think we should support it. Better to simply error out for now maybe?
6d93671
to
3a3138f
Compare
fixes #23689
Notes:
nativeByteOrder32
function in thelibpthread.js
and use the dependency mechanism, but it was always optimized intox => x
.