Skip to content
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

WebAssembly OOB Signal Handlers + Node #14927

Closed
flagxor opened this issue Aug 18, 2017 · 15 comments · Fixed by #27246
Closed

WebAssembly OOB Signal Handlers + Node #14927

flagxor opened this issue Aug 18, 2017 · 15 comments · Fixed by #27246
Labels
process Issues and PRs related to the process subsystem. v8 engine Issues and PRs related to the V8 dependency.

Comments

@flagxor
Copy link

flagxor commented Aug 18, 2017

We're rolling out use of signal handlers for WebAssembly Out-of-Bounds checks in V8 6.2.
We've intentionally left the feature off by default in V8, and will be turning it on Chrome side via features.

The reason is that embedders (for instance node.js), may have their own signal handlers which may interact poorly.

The feature is a big win for WebAssembly performance on 64-bit systems 25%-30% speed-up.

To work in node.js, we need someone knowledgeable about the signal handlers in the system to help us.

If node has a signal handler of its own, it's not too much harder than adding:
--wrap-trap-handler
And then be sure to use the implementation we we provide with V8:
v8::V8::RegisterDefaultSignalHandler()
(Eric CC'ed can help with the particulars)

If there's already a handler (or if some modules have them?), things might be more complex, but not too bad.

Eric Holk is a good contact for this feature on the WebAssembly side.

@hashseed
Copy link
Member

@bnoordhuis @trevnorris @indutny @ofrobots @jasnell

adding a few people who might know, or who might know someone who might know.

@eholk
Copy link

eholk commented Aug 18, 2017

Some of the comments here and following are also relevant. The trap handler feature requires some more support from the array buffer allocator.

@indutny
Copy link
Member

indutny commented Aug 18, 2017

I believe SIGTRAP handling could be done in user code via public API (process.on('SIGTRAP')). If this is to be internalized, that would be a major change.

cc @nodejs/v8 just in case.

@bnoordhuis
Copy link
Member

I looked at the trap handler code earlier this week and I believe the idea is to catch SIGSEGV on out-of-bounds loads and stores? Node.js core itself doesn't touch that signal handler but there is a popular module called segfault-handler that does what its name suggests.

Out of curiosity, wouldn't you also need to intercept SIGBUS for unaligned loads and stores?

@mscdex mscdex added process Issues and PRs related to the process subsystem. v8 engine Issues and PRs related to the V8 dependency. labels Aug 18, 2017
@eholk
Copy link

eholk commented Aug 18, 2017

Correct, we catch SIGSEGV to detect out of bounds loads and stores in WebAssembly.

It's up to the embedder to opt in because chaining signal handlers can be tricky to get right. We provide a default signal handler that you can install using v8::V8::RegisterDefaultSignalHandler(), like @flagxor mentioned. This is fine if the process does not use its own signal handler. In case your process has one (like in the case of Chromium), we expose an API that should be called from the signal handler, v8::V8::TryHandleSignal(...).

The segfault-handler package should be able to work with us if they are willing to call TryHandleSignal before doing additional processing. We'll probably have to think harder if we want try to have Node switch from the default handler to segfault-handler on the fly.

So far we are only enabling this feature on Linux x86-64, so SIGSEGV is all we need there.

@indutny
Copy link
Member

indutny commented Aug 18, 2017

Oh, given that there is an existing API for this it shouldn't be a big deal to just call it from Node.js core.

@hashseed
Copy link
Member

Should we reach out to the maintainers of segfault-handler?

@bnoordhuis
Copy link
Member

cc @ddopson - FYI. I'll see if I can send a PR once this lands in node.

@hashseed Done. :-)

@bnoordhuis
Copy link
Member

It doesn't seem like there is anything left to discuss so I'll go ahead and close this out. Reopen if that is mistaken.

@amirbawab
Copy link

amirbawab commented Apr 14, 2019

It's been a while that this issue is closed, but I'm just curious if node (v12.0.0-pre) is benefitting from the trap handling feature in v8.

I am currently experimenting with WebAssembly load/store while enabling --print-wasm-code I can see the bound check happening in the generated x86.

0x3e8b8c8adce0     0  55             push rbp
0x3e8b8c8adce1     1  4889e5         REX.W movq rbp,rsp
0x3e8b8c8adce4     4  6a0a           push 0xa
0x3e8b8c8adce6     6  56             push rsi
0x3e8b8c8adce7     7  488b9e9f000000 REX.W movq rbx,[rsi+0x9f]
0x3e8b8c8adcee     e  488b96a7000000 REX.W movq rdx,[rsi+0xa7]
0x3e8b8c8adcf5    15  4883ea03       REX.W subq rdx,0x3
0x3e8b8c8adcf9    19  b9ffffffff     movl rcx,0xffffffff
0x3e8b8c8adcfe    1e  483bca         REX.W cmpq rcx,rdx             <------- here
0x3e8b8c8add01    21  0f8308000000   jnc 0x3e8b8c8add0f  <+0x2f>    <------- 
0x3e8b8c8add07    27  8b040b         movl rax,[rbx+rcx*1]
0x3e8b8c8add0a    2a  488be5         REX.W movq rsp,rbp
0x3e8b8c8add0d    2d  5d             pop rbp
0x3e8b8c8add0e    2e  c3             retl
0x3e8b8c8add0f    2f  e88cf3ffff     call 0x3e8b8c8ad0a0     ;; wasm stub: ThrowWasmTrapMemOut
OfBounds
0x3e8b8c8add14    34  90             nop
0x3e8b8c8add15    35  0f1f00         nop

While in chromium (trap handling enabled), --print-wasm-code reports the following:

0x1b5fb94812c0     0  55             push rbp
0x1b5fb94812c1     1  4889e5         REX.W movq rbp,rsp
0x1b5fb94812c4     4  6a0a           push 0xa
0x1b5fb94812c6     6  56             push rsi
0x1b5fb94812c7     7  488b5e17       REX.W movq rbx,[rsi+0x17]
0x1b5fb94812cb     b  baffffffff     movl rdx,0xffffffff
0x1b5fb94812d0    10  8b0413         movl rax,[rbx+rdx*1]
0x1b5fb94812d3    13  488be5         REX.W movq rsp,rbp
0x1b5fb94812d6    16  5d             pop rbp
0x1b5fb94812d7    17  c3             retl
0x1b5fb94812d8    18  e875fdffff     call 0x1b5fb9481052     ;; wasm stub: ThrowWasmTrapMemOut
OfBounds
0x1b5fb94812dd    1d  90             nop
0x1b5fb94812de    1e  6690           nop

Also while debugging v8/src/compiler/wasm-compiler.cc the function call use_trap_handler() in WasmGraphBuilder::BoundsCheckMem(...) resulted in false in node, which ends up creating the extra bounds checking nodes in the graph, but the function call returns true for chromium, omitting those nodes.

Finally, browsing the segfault-handler library, I couldn't find the code which integrates the v8 feature API.

Question: Is it possible to enable trap handling in Node? If so, is it possible to post the PR link?

Thank you for your time -- Amir

FYI, here's the dummy code executed in wat:

(module
  (memory 1)
  (func
    (export "main")
    (result i32)
    (i32.load 
      (i32.const -1)
    )
  )
)

@devsnek
Copy link
Member

devsnek commented Apr 14, 2019

we could enable this but there is a serious issue of someone overriding the SIGSEGV handler. although i wouldn't normally recommend this, it might make sense to just make your own native module to enable this.

#include <node.h>
#include <v8.h>

void Init(v8::Local<v8::Object> exports) {
  v8::V8::EnableWebAssemblyTrapHandler(true);
}

NODE_MODULE(the_module, Init)

just node-gyp this up and require() it and you should be good to go.

@amirbawab
Copy link

@devsnek thank you for your answer and example. I tested your code and it works :)

@addaleax
Copy link
Member

I guess we could make that the default and require addons that provide segfault handlers to make the necessary calls into V8?

@devsnek
Copy link
Member

devsnek commented Apr 14, 2019

@addaleax I'm just concerned about what kind of cascading issues could happen from wasm not properly reporting oob. there is a reason it's a trap after all.

@ofrobots
Copy link
Contributor

IMO we should optimize for the common/expected case rather than the edge cases. We shouldn't make everyone's code run slow just because there may be the possiblity that someone is overriding the SIGSEGV signal handler.

There is a lot of precedent here. For example, I can link a JNI library into my JVM application that overrides the signal handers that the JIT depends on. All sorts of cascading failures may occur as a result. The expected way users are supposed to use signal handlers in native code is via the officially supported way to chain signal handlers.

IMO, we should offer a chaining signal handler API in node, and switch the default to use trap handlers for wasm code – and not necessarily in that order.

devsnek added a commit to devsnek/node that referenced this issue May 16, 2019
This uses SIGSEGV handlers to catch WASM out of bound (OOB) memory
accesses instead of inserting OOB checks inline, resulting in a 25%-30%
speed increase.

Note that installing a custom SIGSEGV handler will break this, resulting
in potentially scary behaviour.

Refs: nodejs#14927

PR-URL: nodejs#27246
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
pull bot pushed a commit to shakir-abdo/node that referenced this issue May 16, 2019
This uses SIGSEGV handlers to catch WASM out of bound (OOB) memory
accesses instead of inserting OOB checks inline, resulting in a 25%-30%
speed increase.

Note that installing a custom SIGSEGV handler will break this, resulting
in potentially scary behaviour.

Refs: nodejs#14927

PR-URL: nodejs#27246
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
process Issues and PRs related to the process subsystem. v8 engine Issues and PRs related to the V8 dependency.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants