Bun.sql getters: do not report a still-pending exception as uncaught in debug builds - #37329
Bun.sql getters: do not report a still-pending exception as uncaught in debug builds#37329robobun wants to merge 2 commits into
Conversation
…bug builds defaultBunSQLObject and constructBunSQLObject called reportUncaughtExceptionAtEventLoop while the exception thrown by requireId was still pending on the VM. That runs the uncaught exception machinery (process._fatalException lookup, error printing) with an exception set, which trips JSC's exception scope assertions and aborts the debug build, for example when Bun.sql is first touched with the stack nearly exhausted. It also marked a caught error as unhandled. The exception already propagates to the property access through reifyStaticProperty, so just let RETURN_IF_EXCEPTION handle it.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughThe SQL constructors no longer report initialization exceptions through debug-only event-loop handling. A subprocess regression test covers stack exhaustion in lazy ChangesSQL exception handling
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/js/sql/sql.test.ts`:
- Around line 12822-12828: Remove the filteredStderr transformation in the
subprocess test and assert the raw stderr value directly. Update the expectation
associated with the stdout RangeError/function assertion to require stderr to be
empty, preserving the existing stdout check.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 7c047ed7-efd7-464f-8587-743a5d9f9f70
📒 Files selected for processing (2)
src/jsc/bindings/BunObject.cpptest/js/sql/sql.test.ts
💤 Files with no reviewable changes (1)
- src/jsc/bindings/BunObject.cpp
|
Applied the stderr suggestion in b51acc1: the new tests now assert the raw stderr is empty instead of filtering the old ASAN banner out. Checked that this holds on the debug ASAN build (the harness passes allow_user_segv_handler=1 through bunEnv, and the current build prints nothing at startup even without it); the three tests still pass repeatedly under bun bd test. |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Confirmed, this is a duplicate. The same two-block removal in Two notes for whichever of them lands, from verifying this fix against the currently pinned WebKit:
|
What does this PR do?
Fixes a debug-build abort found by fuzzing. The first access of
Bun.sql,Bun.postgresorBun.SQLruns a lazy property builder (defaultBunSQLObject/constructBunSQLObjectinBunObject.cpp) that loads the internalbun:sqlmodule. If that load throws (the fuzzer case: the property is first touched from the bottom of a runaway recursion, so entering the module body throwsRangeError: Maximum call stack size exceeded), the builder had a#if BUN_DEBUGblock that calledreportUncaughtExceptionAtEventLoopwhile the exception was still pending on the VM, and only then fell through toRETURN_IF_EXCEPTION.Every other caller of that function clears the exception first. Running the uncaught exception machinery with one still set does a
process._fatalExceptionlookup and error printing on a VM that has an exception pending, which trips JSC's exception scope assertions. Depending on what stateprocessis in at that point, the abort surfaces asStructure::storedPrototype(object->structure() == this, sincesetUpStaticFunctionSlotsees the pre-existing exception right after reifying_fatalException), as theEXCEPTION_ASSERTinJSObject::get, or asassertNoExceptionExceptTerminationfurther down, which is why the fuzzer saw it as flaky. It also counted an error the user went on to catch as unhandled (exit code 1, or exit code 7 when it happened inside anuncaughtExceptionhandler).The fix is removing the two debug-only blocks. The exception from
requireIdalready propagates to the property access:reifyStaticPropertyskips theputDirectwhen the builder returns empty andsetUpStaticFunctionSlotreports the slot as missing, so the access throws the RangeError, the property stays lazy, and the next access loads the module normally. Release builds never had the extra report, so their behavior is unchanged.How did you verify your code works?
The fuzzer script (a constructor that recurses into itself and calls
Bun.postgres(this)in atry/catchon the way back up) aborts on an unfixed debug build with thestoredPrototypeassertion, and exits 0 with this change.Added three tests to
test/js/sql/sql.test.tsthat touchBun.sql,Bun.postgresandBun.SQLfrom an exhausted stack in a subprocess and check that the access throws the RangeError, that a later access returns the function, and that the process exits 0 with nothing on stderr. On an unfixed debug build the subprocess aborts and all three fail; with this change they pass. Since the removed code was debug-only, the tests also pass on a release build. Also ran the repro withBUN_JSC_validateExceptionChecks=1, which is clean.