I'm curious if the macOS 14.4 change referenced in https://blogs.oracle.com/java/post/java-on-macos-14-4 breaks Wasmtime. Anyone has an apple silicon mac and updated to macOS 14.4 to test it?
what do you need to be run?
I'm pretty certain that this won't affect Wasmtime: we don't actually JIT code at runtime. Instead, we AOT compile all code in a module/component before starting execution
We do still use the jit permissions for mapping the compiled code as executable, right?
Ramon Klass said:
what do you need to be run?
Run any wasm module which does an out of bound memory access and check that it gives an error message about this rather than getting immediately SIGKILLed before the signal handler can catch the out of bounds access.
I ran my basic integration tests locally which build a component and check its functions against expected outputs, was green
how do I access oob?
(in rust)
nvm I overthought the problem, I'll add a check to my code
Try this:
(module
(type (;0;) (func (result i32)))
(func $foo (type 0) (result i32)
i32.const 0
i32.load8_u offset=16777216)
(table (;0;) 1 1 funcref)
(memory (;0;) 16)
(global $__stack_pointer (mut i32) (i32.const 1048576))
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "foo" (func $foo))
(export "__data_end" (global 1))
(export "__heap_base" (global 2)))
wasmtime run
should accept .wat
text files.
wasmtime run example.wat (with that wat) exits immediately without printing anything, is that the desired behavior?
We do still use the jit permissions for mapping the compiled code as executable, right?
We do, yes. If I understand the problem correctly, that is entirely ok. (And it better be, because otherwise most every JIT out there would be broken, including Safari's.)
What the JVM seems to be doing is to map a region as WO, but not guarantee that the VM won't try to access it in other ways while it's mapped that way. They then rely on signal handlers to catch these kinds of accesses—presumably by making them wait until the mapping has changed?
If that understanding is correct, then that seems like a clever hack, but also not something that'd be all too common in JITs
Ramon Klass said:
wasmtime run example.wat (with that wat) exits immediately without printing anything, is that the desired behavior?
Forgot that you have to do wasmtime run --invoke foo example.wat
as I named the sole function foo
.
Error: failed to run main module `example.wat`
Caused by:
0: failed to invoke `foo`
1: error while executing at wasm backtrace:
0: 0x6e - <unknown>!foo
2: memory fault at wasm address 0x1000000 in linear memory of size 0x100000
3: wasm trap: out of bounds memory access
so everything's fine
Great! Thanks for testing!
What the JVM seems to be doing is to map a region as WO, but not guarantee that the VM won't try to access it in other ways while it's mapped that way. They then rely on signal handlers to catch these kinds of accesses—presumably by making them wait until the mapping has changed?
We map the guard pages as PROT_NONE
and then use a signal handler to catch out-of-bounds accesses to the linear memory. What is exactly the difference with what the JVM does?
looking at the JVM bug and the man page for pthread_jit_write_protect_np, it seems that macOS provides a mechanism where one can mmap some memory with MAP_JIT
and then flip a global (per-thread?) flag with a pthread API that makes it either writable or executable, but never both. The reproducer at the end of the JVM bug shows that the new SIGKILL case is exactly when the global jit-mode is not-writable and one has any write segfault
Wasmtime doesn't use this mechanism, rather it uses individual mmaps for modules' code memory and mprotects them when publishing
see in particular this sequence and here
so I think we aren't affected (and, empirically, I upgraded to macOS 14.4 on aarch64 recently and haven't seen test failures)
Last updated: Dec 23 2024 at 13:07 UTC