Repository navigation
Conversation
… caller
A failing console.assert aborted a debug or ASAN build under
BUN_JSC_validateExceptionChecks=1:
ERROR: Unchecked JS exception:
This scope can throw a JS exception: messageWithTypeAndLevel @ src/jsc/bindings/ConsoleObject.cpp:38
But the exception was unchecked as of this scope: consoleProtoFuncAssert @ vendor/WebKit/Source/JavaScriptCore/runtime/ConsoleObject.cpp:218
oven-sh/WebKit#790 changes the console host functions in JavaScriptCore.
assert holds no ThrowScope. The eight other functions that hold one
release it before they call the ConsoleClient hook.
WEBKIT_VERSION points at the preview build of that PR. Move it to the
merged commit before this merges.
test/js/bun/jsc/exception-checks.test.ts gets four console.assert rows.
Collaborator
Author
|
Updated 5:23 PM PT - Oct 10th, 2026
❌ @robobun, your commit f7dc2c2 has 1 failures in
🧪 To try this PR locally: bunx bun-pr 44950That installs a local version of the PR into your bun-44950 --bun |
Collaborator
Author
|
Status
|
This was referenced Oct 11, 2026
This branch has not been deployed
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.
Problem
console.assertaborts a debug or ASAN build underBUN_JSC_validateExceptionChecks=1(CI's ASAN lane sets it):But the exception was unchecked as of this scope: consoleProtoFuncAssert @ runtime/ConsoleObject.cpp:218.consoleProtoFuncAssert(JavaScriptCore) holds aThrowScopeacross Bun's console hook and returns with no check or release. The hook can throw and has its own scope since Add jsc-exception-lint and fix the missing exception checks it finds #40410.Fix
assertholds no scope. The eight others callscope.release()before the hook, so their caller owns the check.WEBKIT_VERSIONis that PR's preview build (the pin plus one commit). Draft until the pin can move to the merged commit.test/js/bun/jsc/exception-checks.test.ts(4 new rows, each exits 134 on the current pin). Also the console suites under the validator.Background
ThrowScopedestructor marks a check as needed unless it returns to JIT code. The next unreleased scope asserts on that mark.RETURN_IF_EXCEPTIONafter each call (a load and a branch in release code,scope.release()is free).Downsides
console.assertno longer polls VM traps. Its loop does (check_traps). A Worker spinning inconsole.assert(true)terminates in 10 of 10 runs at both pins.assertshrinks from 522 to 404 bytes, the other eight are identical.Notes
Builds. "Current pin" is
0c06faadf65bf8e8c8ad3a5a8aca83e1e9ed653f. The preview isautobuild-preview-pr-790-cc38fc87: 1 commit on top of the pin,Source/JavaScriptCore/runtime/ConsoleObject.cpp+11/-3, no other file. The preview release has the same 42 assets as the release of the pin. All runs below are debug ASAN builds of this branch on Linux x64 that differ only in the WebKit build.Fail-before on the current pin, one of the four rows:
With the preview build:
8 pass, 0 fail.Forms. Each run alone under the validator:
console.assert(false),console.assert(),console.assert(false, "x"),console.assert(0, {a:1}),console.assert(null, "%s:%d", "a", 1),console.assert("", new Error("e")),Reflect.apply(console.assert, console, [false, "x"]),[0].forEach(console.assert),JSON.stringify({ toJSON: console.assert }). 9 of 9 exit 134 on the current pin. 0 of 9 on the preview.console.assert(true)exits 0 on both.The 11 exits that no test can hold today.
count,countReset,profile(2),profileEnd(2),takeHeapSnapshot(2),time,timeLog,timeEnd. Their Bun hooks declare noThrowScope, so nothing marks a check after they return.scripts/jsc-exception-linton the JavaScriptCore file, with summaries forConsoleClient.cpp,ScriptArguments.cppandScriptCallStackFactory.cpp: 12 findings before (allunchecked-exit, one for each exit), 0 after.ThrowScopewithRELEASE_AND_RETURNin each of the eight Bun hooks. One snippet for each exit, each alone under the validator. 12 of 12 abort on the current pin, each at its own scope (consoleProtoFuncCount @ ConsoleObject.cpp:235,consoleProtoFuncTime @ :326, and so on). 0 of 12 abort on the preview.Simulated throws for each call under the validator (gdb hit count on
JSC::ThrowScope::simulateThrow, 1,001 calls minus 101 calls, divided by 900).console.count("x"): 0 before and after.console.log("x"): 0 and 0.console.timeLog("l", {}): 5 and 5.console.assert(true): 0 and 0.console.assert(false): abort at the first call before, 0 after. In a validator build each of the 11 sibling call sites now also stores one flag byte (m_isReleased).Release code.
ConsoleObject.cppof the pin and of the WebKit PR, each compiled as one file with clang 23.1.2 and the flags of thebun-webkit-linux-amd64-ltobuild (-O3, without-flto).consoleProtoFuncAssert: 522 to 404 bytes, 149 to 119 instructions. The path ofconsole.assert(true)through it: 55 to 46 instructions, 8 to 7 conditional branches. The other 26 functions of the file: 0 differingobjdumplines. I did not make a release build of Bun with the preview.VM traps.
RETURN_IF_EXCEPTIONalso handles pending VM traps (termination, the debugger, the watchdog). The removed one inassertwas such a poll.for (let i = 0; i < n; i++) console.assert(true)compiles toloop_hint,check_traps, ...,call_ignore_result, so the loop polls on each iteration. Worker test: the worker posts one message and spins infor (;;) console.assert(true), the parent waits 300 ms and callsterminate(). Interleaved, 10 runs for each build: 10 of 10 terminate on both. Median 380 ms (241 to 491) on the current pin, 430 ms (237 to 550) on the preview. The difference is inside the spread.Other suites on the preview build, with
BUN_JSC_validateExceptionChecks=1.test/js/web/console/,test/js/bun/console/andtest/js/bun/jsc/exception-checks.test.ts: 109 pass, 1 skip, 2 todo, 0 fail. Node'stest/js/node/test/parallel/test-console-*.js: 16 of 16 exit 0.Not changed.
console.takeHeapSnapshot()still aborts under the validator. Its cause is in Bun:JSC__JSGlobalObject__generateHeapSnapshot @ src/jsc/bindings/bindings.cpp:4108is unchecked insrc/jsc/JSValue.rs:1091. The WebKit change only closes the two exits inconsoleProtoFuncTakeHeapSnapshotthat console.takeHeapSnapshot: report snapshot parse failures instead of aborting #37070 works around.console.assert(false, "x")printsx. Node.js printsAssertion failed: x(console.assert() with message should include "Assertion failed" alongside message #19953).[policy-decision:webkit] gate passed · iteration 0 · 2 files touched
passes on PR (with fix)
diff hotspot
gate history · 1 passed · 0 rejected · iteration 0
evidence per changed file