Bug 202786

Summary: Wasm engine segmentation fault
Product: WebKit Reporter: Jan M <mail>
Component: WebAssemblyAssignee: Nobody <webkit-unassigned>
Status: RESOLVED FIXED    
Severity: Normal    
Priority: P2    
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: macOS 10.12   
Attachments:
Description Flags
JS program illustrating the segfault none

Description Jan M 2019-10-10 02:56:36 PDT
Created attachment 380620 [details]
JS program illustrating the segfault

I'm running the prebuilt jsc binaries available through JSVU: https://github.com/GoogleChromeLabs/jsvu
specifically JavaScriptCore version: v250961.
from URL: https://s3-us-west-2.amazonaws.com/minified-archives.webkit.org/mac-highsierra-x86_64-release/250961.zip

Consider the following Wasm (wat) program:

(module
  (type $0 (func (result f32)))
  (memory $0 2 41_018)
  (global $0 i32 (i32.const -1_329_474_845))
  (func $0
    (type 0)
    (f64.const 0.0)
    (f64.const 0.0)
    (i32.const 0)
    (select)
    (loop (result f32) (f32.const 0.0) (global.get 0) (br_if 0))
    (f64.promote_f32)
    (f64.ne)
    (f32.load offset=0 align=1)
  )
  (export "runf32" (func 0))
)

If I translate it to wasm and inline it in a minimal JS-program that merely calls the exported function:

let importObject = { imports: { } };
let buffer = new Uint8Array([ 0,97,115,109,1,0,0,0,1,5,1,96,0,1,125,3,2,1,0,5,6,1,1,2,186,192,2,6,10,1,127,0,65,227,165,135,134,123,11,7,10,1,6,114,117,110,102,51,50,0,0,10,42,1,40,0,68,0,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,65,0,27,3,125,67,0,0,0,0,35,0,13,0,11,187,98,42,0,0,11 ]);

let m = new WebAssembly.Instance(new WebAssembly.Module(buffer), importObject);
m.exports.runf32();

I consistently segfault JavaScriptCore.
Compare with other JS/wasm engines:

$ timeout 10 v8 jscissue-min2.js 
$ timeout 10 sm jscissue-min2.js 
$ timeout 10 ch jscissue-min2.js 
$ jsc jscissue-min2.js 
/Users/jmid/.jsvu/jsc: line 2: 35687 Segmentation fault: 11  DYLD_FRAMEWORK_PATH="/Users/jmid/.jsvu/engines/javascriptcore" DYLD_LIBRARY_PATH="/Users/jmid/.jsvu/engines/javascriptcore" "/Users/jmid/.jsvu/engines/javascriptcore/javascriptcore" "$@"
$ 

The program is just an infinite loop when interpreted correctly, so the other engines are run with a timeout of 10 sec.

Running from a Linux Docker image I experience the same behaviour (again jsc installed through jsvu):
$ jsc jscissue-min2.js 
Segmentation fault
$ uname -a
Linux 496d66cd2709 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 GNU/Linux
$ 

Interestingly, when I tried to constant-fold the (select) from the beginning the error does trigger.
This was also the case for me if I turn the global look-up inside the loop into an equivalent i32.const.
These suggest that it may be some pattern matching optimization that is faulty.
Comment 1 Jan M 2019-10-10 03:20:47 PDT
Typo: Interestingly, when I tried to constant-fold the (select) from the beginning the error does *not* trigger.

I just tried the latest JavaScriptCore version: v250962.
from URL: https://s3-us-west-2.amazonaws.com/minified-archives.webkit.org/mac-highsierra-x86_64-release/250962.zip
and the example still segfaults jsc.
Comment 2 Jan M 2019-10-10 05:40:07 PDT
Also segfaults v250964.
Comment 3 Jan M 2019-10-11 08:14:10 PDT
Also segfaults v251008.
Comment 4 Alexey Proskuryakov 2019-10-11 14:58:20 PDT
FWIW, this appears to hang WebContent in Safari, but I don't observe a crash.
Comment 5 Jan M 2019-10-12 03:51:35 PDT
Yes, the example also just hangs Safari 12.1.2 (12607.3.10) on my MacBook Pro
(suitably inlined in a minimal HTML document).
This is the expected behaviour and agrees with V8, SpiderMonkey and Chakra's interpretation of the infinite Wasm loop (run with a 10sec timeout).

Since the example has crashed every nightly build I've tried for the past three days, I guess it has been introduced into WebKit since the release Safari is built with.
Comment 6 Jan M 2019-10-12 03:55:11 PDT
With a ulimit -c unlimited I get a core dump that can be loaded with lldb.
Here's a stack trace from the nightly build:

$ lldb -c /cores/core.75180 
(lldb) target create --core "/cores/core.75180"
Core file '/cores/core.75180' (x86_64) was loaded.
(lldb) bt
* thread #1, stop reason = signal SIGSTOP
  * frame #0: 0x0000020be155cb2c
    frame #1: 0x0000020be155cd38
    frame #2: 0x00000001094d82af JavaScriptCore`vmEntryToJavaScript + 200
    frame #3: 0x000000010a00639c JavaScriptCore`JSC::callWebAssemblyFunction(JSC::JSGlobalObject*, JSC::CallFrame*) + 1116
    frame #4: 0x0000020be155c16b
    frame #5: 0x00000001094eec90 JavaScriptCore`llint_entry + 92211
    frame #6: 0x00000001094eec90 JavaScriptCore`llint_entry + 92211
    frame #7: 0x00000001094eec90 JavaScriptCore`llint_entry + 92211
    frame #8: 0x00000001094eec90 JavaScriptCore`llint_entry + 92211
    frame #9: 0x00000001094eec90 JavaScriptCore`llint_entry + 92211
    frame #10: 0x00000001094d82af JavaScriptCore`vmEntryToJavaScript + 200
    frame #11: 0x0000000109b18ce9 JavaScriptCore`JSC::Interpreter::executeProgram(JSC::SourceCode const&, JSC::CallFrame*, JSC::JSObject*) + 11785
    frame #12: 0x0000000109da2668 JavaScriptCore`JSC::evaluate(JSC::CallFrame*, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&) + 328
    frame #13: 0x000000010920864c javascriptcore`jscmain(int, char**) + 3804
    frame #14: 0x000000010920775b javascriptcore`main + 27
    frame #15: 0x00007fff90d67235 libdyld.dylib`start + 1
(lldb)
Comment 7 Jan M 2019-10-23 12:07:12 PDT
...and the segfault continues with v251480.

Slightly more interesting, I've found out that the error
does not occur in "249479" (which was laying around in an old Docker container).

That indicates a commit between versions 249479 and 250961 introduced the bug.
Comment 8 Jan M 2019-11-06 03:37:06 PST
Being a newcomer to this system I probably registered the bug wrongly.
I've just changed 'Component': 'JavaScriptCore' -> 'WebAssembly'.
Comment 9 Jan M 2019-11-08 00:46:20 PST
I've managed to reduce the example further:

(module
  (type $0 (func (result f32)))
  (global $0 i32 (i32.const 1))
  (func $0
    (type 0)
    (f32.const 0.0)
    (f32.const 0.0)
    (i32.const 0)
    (select)
    (loop (result f32) (f32.const 0.0) (global.get 0) (br_if 0))
    (drop)
  )
  (export "runf32" (func 0))
)

Basically it's a 'select' followed by an infinite loop that looks up a global.

The corresponding JS (also reduced):

let buffer = new Uint8Array([ 0,97,115,109,1,0,0,0,1,5,1,96,0,1,125,3,2,1,0,6,6,1,127,0,65,1,11,7,10,1,6,114,117,110,102,51,50,0,0,10,30,1,28,0,67,0,0,0,0,67,0,0,0,0,65,0,27,3,125,67,0,0,0,0,35,0,13,0,11,26,11 ]);

let m = new WebAssembly.Instance(new WebAssembly.Module(buffer));
m.exports.runf32();


This continues to segfault the nightly builds (from jsvu), tested with 252179 and 252135.
As mentioned, it doesn't segfault 249479 where it just runs an infinite loop, as expected.
Comment 10 Jan M 2020-10-09 15:45:25 PDT
I can add that this example now loops (as expected) with version 267333.

I'll therefore change the status to 'resolved'.