Your wasm fix for v8 has already been merged into node 26.x and is in the
queue for 24.x - I've committed your diff, because why wait for upstream :-)

Thanks!

On 7/12/26 5:10 PM, Fabien Romano wrote:

On 7/11/26 13:09, Volker Schlecht wrote:

On 7/10/26 10:43 AM, Fabien Romano wrote:
[...]
https://chromium-review.googlesource.com/c/v8/v8/+/8063803
[...]

For now, I think we have to disable regexp JIT.
Attached is the diff I'm currently testing. Did I get it right?
I am inclined to commit this sooner rather than later, because it
looks like this will fix the build issues we've been seeing for the
chromiums.

Sorry, I'm slow at testing all that stuff.

Random build failure seems unrelated to stack feature WASM uses.
So the diff looks good for the reliability issue.

I tried the upstream fix, and it works fine, as expected.

The regexp JIT, someone could check arm64 before we disable all arch.
If it succeeds on arm64, we may disable all arch except this one.
I need to invest more time learning this topic; see the small report below.

Then about how we disable JIT. Thinking twice, we should just switch default.
JIT still built in the engine so someone can do --no-regexp-interpret-all.

The first patch I sent made those read-only, which may produce (seen with d8):
Flag processing error: Contradictory value for readonly flag 
--regexp-interpret-all

The problem is I lost my last node build, oops.
So maybe nodes treat those differently.

Also, after checking carefully, regexp_interpret_all alone is enough.

bool IrRegExpData::ShouldProduceBytecode() {
   return v8_flags.regexp_interpret_all ||
          (v8_flags.regexp_tier_up && !MarkedForTierUp());
}

bool RegExp::CanGenerateBytecode() {
   return v8_flags.regexp_interpret_all || v8_flags.regexp_tier_up;
}

My bad. There is another patch to test.
Actually, I'm not sure which option I prefer (READONLY or not).
Let me know what you think.

To reproduce the crash :

Node uses a hardcoded executable path;
You may have to install the node binary you want to test.
(Tests may use both system and build binaries.)
I'm saying just in case because I was struggling to reproduce ...
Until I reinstall node without the patch. (maybe unrelated, not sure)

cd /usr/ports/lang/node
make retest TEST_TARGET="JOBS=1 JS_SUITES=parallel/test-worker-heap-snapshot 
NATIVE_SUITES= TEST_CI_ARGS='--repeat 100 -p verbose' jstest"

Starting release test-worker-heap-snapshot...
Done running release test-worker-heap-snapshot: pass
Starting release test-worker-heap-snapshot...
Done running release test-worker-heap-snapshot: CRASH
Starting release test-worker-heap-snapshot...
Done running release test-worker-heap-snapshot: pass

On amd64:

cd `make show=WRKSRC`
doas -u _pbuild egdb out/Release/node node.core

Core was generated by `node'.
Program terminated with signal SIGTRAP, Trace/breakpoint trap.
#0  0x00000092c52fcb37 in 
v8::internal::RegExpMacroAssemblerX64::CheckStackGuardState(unsigned long*, 
unsigned long, unsigned long, unsigned long) ()
[Current thread is 1 (process 294920)

(gdb) disassemble /r $pc-32,$pc
Dump of assembler code from 0x92c52fcb17 to 0x92c52fcb37:
    0x00000092c52fcb17 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+167>:     
  4e ff 48 83             rex.WRX decq -0x7d(%rax)
    0x00000092c52fcb1b 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+171>:     
  c4                      (bad)
    0x00000092c52fcb1c 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+172>:     
  30 5b 41                xor    %bl,0x41(%rbx)
    0x00000092c52fcb1f 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+175>:     
  5c                      pop    %rsp
    0x00000092c52fcb20 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+176>:     
  41 5d                   pop    %r13
    0x00000092c52fcb22 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+178>:     
  41 5e                   pop    %r14
    0x00000092c52fcb24 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+180>:     
  41 5f                   pop    %r15
    0x00000092c52fcb26 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+182>:     
  41 5b                   pop    %r11
    0x00000092c52fcb28 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+184>:     
  5d                      pop    %rbp
    0x00000092c52fcb29 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+185>:     
  4c 33 1c 24             xor    (%rsp),%r11
    0x00000092c52fcb2d 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+189>:       4c 
3b 1d dc c7 41 01    cmp    0x141c7dc(%rip),%r11        # 0x92c6719310 
<__retguard_658>
    0x00000092c52fcb34 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+196>:       74 
09                   je     0x92c52fcb3f 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+207>
    0x00000092c52fcb36 
<_ZN2v88internal23RegExpMacroAssemblerX6420CheckStackGuardStateEPmmmm+198>:     
  cc                      int3
End of assembler dump.

The %rsp changes came from v8/src/regexp/regexp-macro-assembler.cc
All architecture behaves differently, but they share this return address change.

int NativeRegExpMacroAssembler::CheckStackGuardState(
     Isolate* isolate, int start_index, RegExp::CallOrigin call_origin,
     Address* return_address, Tagged<InstructionStream> re_code,
     Address* subject, const uint8_t** input_start, const uint8_t** input_end,
     uintptr_t gap) {
...
     if (!code_handle->SafeEquals(re_code)) {  // Return address no longer valid
       // Overwrite the return address on the stack.
       intptr_t delta = code_handle->address() - re_code.address();
       Address new_pc = old_pc + delta;
       // TODO(v8:10026): avoid replacing a signed pointer.
       PointerAuthentication::ReplacePC(return_address, new_pc, 0);
     }
...
}

Arm64 uses a stub to call native functions, and this stub doesn't use retguard.
If I'm reading this correctly, it should be able to change the return address.
Because it will not change the C++ function but the stub one.

This is complex and hard to reproduce, but I got this crash in a build.
That's why I think we have to disable this regexp JIT for now.

./devel/codex
./lang/deno
./lang/node
./www/chromium
./www/iridium
./www/ungoogled-chromium

I have no idea how long for the WASM fix to land upstream.

I think the process should be producing patches for chromium first.

There is a lang/v8 (150.0.7871.100) port for test purposes only.
I didn't try to apply other patches, which should fix tests.
I didn't review test results yet.
I left a previous test.log run on amd64 inside the port.

cd lang/v8 && make makesum && make MAKE_JOBS=8 test

If you are missing dependencies, this should be enough (more than needed).
cd www/chromium && make prepare

===
=== 26 tests failed
===
15940 base tests produced 14817 (92%) non-filtered tests
14817 tests ran

./x11/qt5/qtwebengine

This one is the oldest and looks not affected by new patches.

./x11/qt6/qtwebengine

USE_NOBTCFI=yes, v8_enable_cet_ibt=false
This one isn't affected by the WASM jump table fix.
Other patches may apply.


Did I miss one?
Don't think so. lang/deno and devel/codex are chasing the latest v8
and are typically very close to the chromiums. I don't know about
qtwebengine, but lang/node is much more conservative however.

And maybe someday we will also have www/electron.
Problems are more about the ecosystem than Electron itself.

Reply via email to