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)

60 Branch
defect

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
Component: Untriaged → JavaScript Engine
Product: Firefox → Core
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.
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; }
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?
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
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)
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)
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.)
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)
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.)
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
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 ..
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
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)
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.
Where can I find those memory protection tricks for out of bound access?
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)
Component: JavaScript Engine → Javascript: Web Assembly
Priority: -- → P3
(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
(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
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!
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.
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
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.
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.
If it helps, bug 1495149 removes signal handler usage from asm.js.
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...
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)
QA Contact: pastith
Severity: normal → S3

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.