Fabien Romano
unread,6:18 AM (16 hours ago) 6:18 AMSign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to v8-...@googlegroups.com
Hi,
Second message attempt (I first tried with the online form).
On OpenBSD 7.9-current, with Node 24.18.0 and Yarn 4.17.0.
Note that this could affect any OS(x64) on any WASM code.
Still, the conditions to reproduce are very specific.
The command "yarn install" randomly fails with (example):
RangeError: ansi-styles@npm:3.2.1: Maximum call stack size exceeded
at wasm-function[104]:0xbc29
at wasm-function[104]:0xbc9d
... 7506 frames of wasm-function[104] ...
at wasm-function[188]:0x11867
at new PI (.../yarn.js:148:193125)
at new hs (.../yarn.js:148:199501)
at Object.Dit (.../yarn.js:191:212680)
at async e.fetchFromNetwork (.../yarn.js:693:3984)
at async e.fetchPackageFromCache (.../yarn.js:198:3374)
at async e.fetch (.../yarn.js:693:3337)
With dchecks enabled, it gets caught on:
Fatal error in ../deps/v8/src/wasm/jump-table-assembler.h, line 163
Debug check failed: kJumpTableSlotSize == jtasm.pc_offset() (16 vs. 24).
Trace/BPT trap (core dumped)
This needs x64/amd64 with V8_ENABLE_CET_IBT and a code-space layout where the
compiled Wasm target is outside the rel32 range of its primary jump-table slot.
With CET, an x64 Wasm jump-table slot is 16 bytes:
endbr64; nop; jmp rel32; int3 padding.
The buggy path tries a direct jump first. EmitJumpSlot() writes endbr64; nop
before checking rel32 reachability. If the target is too far, it returns false
after advancing pc_ by 8 bytes. The far-jump fallback then emits another
endbr64; nop and the final jmp starts at slot+16, overwriting the next slot.
Keep EmitJumpSlot() side-effect-free on failure and compute the rel32
displacement from the real jmp location, i.e. after the CET marker.
Can someone follow the process of submitting and reviewing the below diff?
Regarding CLA, the below diff is just a demonstration and not a contribution.
I think "2 * kInt32Size" should be replaced by a symbol.
Please let me know when it get fixed so we can cherry-pick the proper diff.
Thanks,
--
Fabien Romano
Index: deps/v8/src/wasm/jump-table-assembler.cc
--- deps/v8/src/wasm/jump-table-assembler.cc.orig
+++ deps/v8/src/wasm/jump-table-assembler.cc
@@ -115,15 +115,14 @@ void JumpTableAssembler::EmitLazyCompileJumpSlot(uint3
bool JumpTableAssembler::EmitJumpSlot(Address target) {
#ifdef V8_ENABLE_CET_IBT
- uint32_t endbr_insn = 0xfa1e0ff3;
- uint32_t nop = 0x00401f0f;
- emit<uint32_t>(endbr_insn, kRelaxedStore);
- // Add a nop to ensure that the next block is 8 byte aligned.
- emit<uint32_t>(nop, kRelaxedStore);
+ static constexpr int kCodeEntryMarkerSize = 2 * kInt32Size;
+#else
+ static constexpr int kCodeEntryMarkerSize = 0;
#endif
intptr_t displacement =
- target - (pc_ + MacroAssembler::kIntraSegmentJmpInstrSize);
+ target - (pc_ + kCodeEntryMarkerSize +
+ MacroAssembler::kIntraSegmentJmpInstrSize);
if (!is_int32(displacement)) return false;
uint8_t inst[kJumpTableSlotSize] = {
@@ -134,6 +133,13 @@ bool JumpTableAssembler::EmitJumpSlot(Address target)
memcpy(&inst[1], &displacement32, sizeof(int32_t));
// The jump table is updated live, so the write has to be atomic.
+#ifdef V8_ENABLE_CET_IBT
+ uint32_t endbr_insn = 0xfa1e0ff3;
+ uint32_t nop = 0x00401f0f;
+ emit<uint32_t>(endbr_insn, kRelaxedStore);
+ // Add a nop to ensure that the next block is 8 byte aligned.
+ emit<uint32_t>(nop, kRelaxedStore);
+#endif
emit<uint64_t>(*reinterpret_cast<uint64_t*>(inst), kRelaxedStore);
return true;