mprotect-based memory boundary checking#272
Open
kateinoigakukun wants to merge 20 commits intomainfrom
Open
Conversation
3e9e64f to
144c97e
Compare
MaxDesiatov
reviewed
Jan 26, 2026
Member
|
Benchmarks: CoreMark (3 runs each, Iterations/Sec, higher is better) CoreMark is essentially identical between the two branches (well within noise). libsodium (WishYouWereFast) via hyperfine, mean time in ms, lower is better libsodium: Mixed picture, but overall net-positive:
|
MaxDesiatov
approved these changes
Mar 26, 2026
Member
MaxDesiatov
left a comment
There was a problem hiding this comment.
IMO this is good to merge and it unblocks a lot of future work (shared memory for wasip1-threads, JIT/AOT and so on)
e71e628 to
f9bd976
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Use
mprotect-based virtual memory for Wasm linear memory on macOS and Linux.Instead of bounds-checking every load/store in software, reserve the full 4GB address space via
mmap(PROT_NONE)andmprotectcommitted pages as the memory grows. Out-of-bounds accesses hit unmapped guard pages, triggeringSIGSEGV/SIGBUSwhich a registered signal handler converts into a Wasm trap.This adds
Uncheckedvariants of all memory load/store instructions. The translator emits these when the target memory uses mprotect and thememarg.offsetfits within the guard region, skipping the software bounds check entirely.New
EngineConfiguration.memoryBoundsCheckingoption (.auto/.mprotect/.software). Default is.auto, which uses mprotect on supported platforms and falls back to software checks otherwise. Memory64 always uses software checks.Signal Safety
siglongjmpfrom a signal handler does NOT run Swift destructors (deinit,defer,withValueclosures) or ARC release operations on abandoned frames.The direct-threaded path is safe:
wasmkit_tc_startruns the dispatch loop in C trampolines, thememory.withValuelock is released before dispatch begins, and the unchecked instruction handlers (memoryLoadUnchecked/memoryStoreUnchecked) hold no resources. The only Swift scope on the stack iswithUnsafeMutablePointer(to: &self)which merely pins a pointer.The token-threaded path is problematic:
runTokenThreadedImplcontains a Swiftwhile true { try doExecute(...) }loop. A fault during an unchecked memory instruction causessiglongjmpto cut through Swift frames, which is undefined behavior in Swift. If the fault occurs mid-withValueon aMutex-protected resource, the lock is never released.For this reason,
Engine.initwill throwEngineConfigurationErrorwhen a user requests token-threading (including automatically selected one on platforms without direct threading) and explicitmprotect-based bounds checking.