Closed
Bug 1496713
Opened 6 years ago
Closed 24 days ago
TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use (Solaris)
Categories
(Core :: JavaScript: WebAssembly, defect, P5)
Tracking
()
RESOLVED
INCOMPLETE
People
(Reporter: petr.sumbera, Unassigned)
Details
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0
Steps to reproduce:
While running js tests from Firefox 60.2.0esr on Solaris intel I see:
{"action": "suite_start", "pid": 6834, "source": "jittests", "tests": [], "thread": "main", "time": 1538742788.161322}
/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/lib/asm.js:202:15 TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use
Exit code: 3
FAIL - asm.js/testHeapAccess.js
TEST-UNEXPECTED-FAIL | js/src/jit-test/tests/asm.js/testHeapAccess.js | /scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/lib/asm.js:202:15 TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use (code 3, args "--ion-eager --ion-offthread-compile=off") [42.6 s]
{"action": "test_start", "pid": 6834, "source": "jittests", "test": "asm.js/testHeapAccess.js", "thread": "main", "time": 1538742788.213956}
{"action": "test_end", "extra": {"jitflags": "--ion-eager --ion-offthread-compile=off"}, "message": "/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/lib/asm.js:202:15 TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use", "pid": 6834, "source": "jittests", "status": "FAIL", "test": "asm.js/testHeapAccess.js", "thread": "main", "time": 1538742830.813338}
INFO exit-status : 3
INFO timed-out : False
INFO stderr 2> /scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/lib/asm.js:202:15 TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use
/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/lib/asm.js:202:15 TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use
Exit code: 3
...
FAILURES:
--ion-eager --ion-offthread-compile=off asm.js/testHeapAccess.js
asm.js/testHeapAccess.js
--baseline-eager asm.js/testHeapAccess.js
--ion-eager --ion-offthread-compile=off --non-writable-jitcode --ion-check-range-analysis --ion-extra-checks --no-sse3 --no-threads asm.js/testHeapAccess.js
--no-baseline --no-ion asm.js/testHeapAccess.js
TIMEOUTS:
Result summary:
Passed: 1
Failed: 5
Reporter | ||
Updated•6 years ago
|
Component: Untriaged → JavaScript Engine
Product: Firefox → Core
Comment 1•6 years ago
|
||
Thanks for the report. I think the error comes down from this function:
https://searchfox.org/mozilla-central/source/js/src/vm/ArrayBufferObject.cpp#938
Can it be that this is trying to allocate a lot of memory and then this triggers an allocation failure on your machine? If you have access to a debugger, you could step in into this function and see what's going on.
Reporter | ||
Comment 2•6 years ago
|
||
It seems that the function in version 60 looks differently. I have added some debug prints. For the first time it looks fine. Second time it's out of memory:
uint32_t length = buffer->byteLength();
WasmArrayRawBuffer* wasmBuf = WasmArrayRawBuffer::Allocate(length, Some(length));
if (!wasmBuf) {
ReportOutOfMemory(cx);
return false;
}
Comment 3•6 years ago
|
||
It's probably that the mmap or mprotect fails; there's an attempt to trigger a GC in there, but it's only if you have a lot of buffers: https://dxr.mozilla.org/mozilla-esr60/source/js/src/vm/ArrayBufferObject.cpp#135-147
Do you run Firefox with some memory limitations or in a sandbox? Is it a 32 bits or a 64 bits platform?
Reporter | ||
Comment 4•6 years ago
|
||
I have bump into this wile running js tests (Firefox on Solaris intel seems to be more or less fine).
It's 64bit Firefox. But it's run with 32bit address space due:
https://bugzilla.mozilla.org/show_bug.cgi?id=577056#c15
Comment 5•6 years ago
|
||
Interesting, we're probably trying to map a huge block of memory assuming we have 64 bits address space. Can you:
1. check that WASM_HUGE_MEMORY is defined when building? (you can add invalid C++ statements in code that's present only if !WASM_HUGE_MEMORY, for instance: https://dxr.mozilla.org/mozilla-esr60/source/js/src/vm/ArrayBufferObject.cpp#680 )
2. If so, does a build work if you change it from True to False here: https://dxr.mozilla.org/mozilla-esr60/source/js/src/moz.build#687
Flags: needinfo?(petr.sumbera)
Reporter | ||
Comment 6•6 years ago
|
||
WASM_HUGE_MEMORY was used. Don't setting it leads to following. Probably needs more hacking?!
/usr/gcc/7/bin/g++ -o Unified_cpp_js_src13.o -c -I/scratch/userland-gate/components/desktop/firefox/build/amd64/dist/system_wrappers -include /scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/config/gcc_hidden.h -DDEBUG=1 -DENABLE_WASM_GLOBAL -UWASM_HUGE_MEMORY -DJS_CACHEIR_SPEW -DENABLE_SHARED_ARRAY_BUFFER -DEXPORT_JS_API -DJS_HAS_CTYPES '-DDLL_PREFIX="lib"' '-DDLL_SUFFIX=".so"' -DMOZ_HAS_MOZGLUE -I/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src -I/scratch/userland-gate/components/desktop/firefox/build/amd64/js/src -I/scratch/userland-gate/components/desktop/firefox/build/amd64/dist/include -I/scratch/userland-gate/components/desktop/firefox/build/amd64/dist/include/nspr -fPIC -DMOZILLA_CLIENT -include /scratch/userland-gate/components/desktop/firefox/build/amd64/js/src/js-confdefs.h -m64 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -Wall -Wempty-body -Wignored-qualifiers -Woverloaded-virtual -Wpointer-arith -Wsign-compare -Wtype-limits -Wunreachable-code -Wwrite-strings -Wno-invalid-offsetof -Wc++1z-compat -Wduplicated-cond -Wimplicit-fallthrough -Wno-error=maybe-uninitialized -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wformat -Wformat-overflow=2 -Wno-noexcept-type -fno-sized-deallocation -m64 -O3 -Wno-invalid-offsetof -fpermissive -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fno-rtti -ffunction-sections -fdata-sections -fno-exceptions -fno-math-errno -pthread -pipe -g -O -fno-omit-frame-pointer -DFFI_NO_RAW_API -I/usr/lib/amd64/libffi-3.2.1/include -Wno-shadow -Werror=format -fno-strict-aliasing -MD -MP -MF .deps/Unified_cpp_js_src13.o.pp /scratch/userland-gate/components/desktop/firefox/build/amd64/js/src/Unified_cpp_js_src13.cpp
In file included from /scratch/userland-gate/components/desktop/firefox/build/amd64/js/src/Unified_cpp_js_src13.cpp:38:0:
/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit/CodeGenerator.cpp: In member function 'void js::jit::CodeGenerator::visitWasmBoundsCheck(js::jit::LWasmBoundsCheck* ':
/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit/CodeGenerator.cpp:12753:63: error: use of deleted function 'void js::jit::MacroAssembler::wasmBoundsCheck(js::jit::AssemblerX86Shared::Condition, js::jit::Register, js::jit::Register, L) [with L = js::wasm::OldTrapDesc]'
oldTrap(mir, wasm::Trap::OutOfBounds));
^
Flags: needinfo?(petr.sumbera)
Comment 7•6 years ago
•
|
||
Several things here:
We don't support explicit bounds checking on 64-bit builds / we don't support 64-bit builds without WASM_HUGE_MEMORY. And we probably don't want to.
(EDIT: Actually we probably want to, see bug 1518210.)
The comment on bug 577056 referenced above is about Solaris on Sparc, where we have known problems; more about this below.
But comment #0 says this is about Solaris on Intel, where we should be fine in the address space that's available; the problems on Sparc should not be problems on Intel; Solaris should have nothing to do with it. Intel has a sufficiently narrow virtual address space for SpiderMonkey (at the moment). So what's going on here? Is Firefox being built to run in a 32-bit address space on Intel because it observably crashes if it is not built that way, or is this just a holdover from the older Sparc builds?
(About Sparc: Things are not as bad as they used to be and a 32-bit address space should not bne needed if the solution that is used for Sparc on NetBSD and Linux can be made to work on Solaris. There's code in in gc/Memory.cpp that tries to solve the problem of the too-large address space; look for __sparc__ ifdefs. Could these workarounds be made to apply to Sparc/Solaris? There are already some Solaris ifdefs there.)
Reporter | ||
Comment 8•6 years ago
|
||
I have removed limitation to 32-bit address space (on intel) and I still get the same problem. It still get out of memory (WASM_HUGE_MEMORY is defined):
https://dxr.mozilla.org/mozilla-esr60/source/js/src/vm/ArrayBufferObject.cpp#907
(About sparc: I guess that I should investigate outlined possibilities for sparc under Bug 577056)
Comment 9•6 years ago
|
||
Maybe you can find out where the failure comes from? Is this caused by mmap() returning a null pointer indicating failure, or is the failure originating in some other function on the path between this allocating code in ArrayBufferObject and mmap?
If it is mmap failing, is this the platform mmap or some replacement (either from Mozilla or something you use for these builds)?
Also: Other people have had problems with wasm memory on 64-bit systems because their operating systems limit user processes to a fairly small amount of virtual memory (often in the range of 8GB). Since Wasm on 64-bit systems wants a 6GB contiguous range, this is often very tight even for one wasm memory, and impossible for two. On linux, `ulimit -v` tells me what my virtual memory limit is, I don't know what the equivalent is on Solaris though. You should probably investigate this.
(It is possible that Firefox should be made to recognize the ulimit problem so that at least developers can be made aware of the problem via a warning in the console.)
Reporter | ||
Comment 10•6 years ago
|
||
It gets MAP_FAILED after calling MozTaggedAnonymousMmap:
https://dxr.mozilla.org/mozilla-esr60/source/js/src/vm/ArrayBufferObject.cpp#135
(it actually 3x passe before it - it always maps 6442520576 bytes)
Where can look for MozTaggedAnonymousMmap definition? Following seems to be just for Android:
https://dxr.mozilla.org/mozilla-esr60/source/mfbt/TaggedAnonymousMemory.cpp#93
Reporter | ||
Comment 11•6 years ago
|
||
MozTaggedAnonymousMmap seems to be here:
https://dxr.mozilla.org/mozilla-esr60/source/mfbt/TaggedAnonymousMemory.h#73
Where mmap sets errno to EAGAIN:
https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html
Reporter | ||
Comment 12•6 years ago
|
||
I have also tried to increase swap to 256Gigs and mmap no longer fails (though it's insane value). Now it fails differently:
{"action": "suite_start", "pid": 4295, "source": "jittests", "tests": [], "thread": "main", "time": 1539122088.143548}
/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/tests/asm.js/testHeapAccess.js:121:1 Error: Assertion failed: got 3, expected 0
Stack:
@/scratch/userland-gate/components/desktop/firefox/firefox-60.2.0/js/src/jit-test/tests/asm.js/testHeapAccess.js:121:1
Exit code: 3
FAIL - asm.js/testHeapAccess.js
..
Reporter | ||
Comment 13•6 years ago
|
||
Adding MAP_NORESERVE flag to mmap call on Solaris seems to fix memory problem.
https://dxr.mozilla.org/mozilla-esr60/source/js/src/vm/ArrayBufferObject.cpp#136
Not sure why it's not needed on other systems.
Plus still there is the other failure:
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i,j) {i=i|0;j=+j; f64[i>>3] = j; return (~~+f64[i>>3])|0}; return f');
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
assertEq(f(0, 1.3), 1);
assertEq(f(BUF_MIN-8, 2.5), 2);
assertEq(f(BUF_MIN, 3.8), 0); // This assertion fails
Comment 14•6 years ago
|
||
Re the flag, it's possible that Linux normally has some swap overcommit system enabled that works around the problem. Luke, any opinion about whether we should maybe use MAP_NORESERVE for all platforms?
I'll look into the other failure, it may be an issue with a no-jit system.
Flags: needinfo?(luke)
Comment 15•6 years ago
|
||
Hm, the other error is a bounds checking error... the test stores the value in the slot just above the heap limit and then tries to read it again. The write should be ignored silently and the read should produce zero (JS TypedArray semantics). But here we read '3' which is the (coerced) value that we tried to write. This is not good; it indicates that the memory protection tricks that we use use to guard against out-of-bounds accesses are not working properly on this platform.
Reporter | ||
Comment 16•6 years ago
|
||
Where can I find those memory protection tricks for out of bound access?
Comment 17•6 years ago
|
||
I would think that it's important for the readabale/writable subset of the 6gb mapping to be reserved; otherwise there will be a rather easy way to crash the process.
I wonder if the root problem here is that huge PROT_NONE region of the initial 6gb mmap() is being reserved on Solaris but not on Linux. One option might be for the initial 6gb PROT_NONE mapping to be MAP_NORESERVE and then, instead of using mprotect() to enable r/w, we use mmap(MAP_FIXED) to simultaneously enable r/w and make this region reserved.
Flags: needinfo?(luke)
Updated•6 years ago
|
Component: JavaScript Engine → Javascript: Web Assembly
Priority: -- → P3
Comment 18•6 years ago
|
||
(In reply to Petr Sumbera from comment #16)
The signal handler used for (non-Mac) POSIX systems is here:
https://searchfox.org/mozilla-central/source/js/src/wasm/WasmSignalHandlers.cpp#749
Comment 19•6 years ago
|
||
(In reply to Petr Sumbera from comment #16)
> Where can I find those memory protection tricks for out of bound access?
And a fair amount of documentation is here:
https://searchfox.org/mozilla-central/source/js/src/vm/ArrayBufferObject.cpp#601
Reporter | ||
Comment 20•6 years ago
|
||
I see that SetFPRegToNaN() is called from signal handler and on address fp_reg where is 3.8 is written NaN:
https://dxr.mozilla.org/mozilla-esr60/source/js/src/wasm/WasmSignalHandlers.cpp#579
But yet the script still gets back 3!
Comment 21•6 years ago
|
||
To me, that suggests that there's something unusual going on with signal handling on Solaris, so that the updated value is not loaded back into a register when the signal handler returns.
Comment 22•6 years ago
|
||
Yes, it does sound like it.
Are the state registers and per-platform definitions correct on your platform?
https://searchfox.org/mozilla-central/source/js/src/wasm/WasmSignalHandlers.cpp#33-340
Reporter | ||
Comment 23•6 years ago
|
||
If I understand it correctly. When OS gets the signal it stores all registers into memory from where we read it.
It seems to use XMM_sig here
https://dxr.mozilla.org/mozilla-esr60/source/js/src/wasm/WasmSignalHandlers.cpp#138
After we modify the value to NaN and return from signal handler, modified value should be read back into register?! I mean there is no other macro involved? And since the address returned by XMM_sig contains expected float number, the macros is probably ok.
Comment 24•6 years ago
|
||
Yes, that's how it's supposed to work. The question really is whether Solaris reads the register values back from the same area, or expects some other action to be taken to set those values.
Comment 25•6 years ago
|
||
If it helps, bug 1495149 removes signal handler usage from asm.js.
Reporter | ||
Comment 26•6 years ago
|
||
Just side note that I looked at Firefox 52.9 where the same test works for me. The only difference seemed that it's 32bit binary. But there is more. It doesn't seem to call signal handler (HandleFault) at all...
Updated•5 years ago
|
Priority: P3 → P5
Summary: TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use → TypeError: asm.js link error: Unable to prepare ArrayBuffer for asm.js use (Solaris)
Updated•3 years ago
|
QA Contact: pastith
Updated•2 years ago
|
Severity: normal → S3
Comment 27•24 days ago
|
||
asm.js is not a priority these days. Closing this bug.
Status: UNCONFIRMED → RESOLVED
Closed: 24 days ago
Resolution: --- → INCOMPLETE
You need to log in
before you can comment on or make changes to this bug.
Description
•