Fix unchecked exception when Bun.plugin target coercion throws#31017
Fix unchecked exception when Bun.plugin target coercion throws#31017robobun wants to merge 2 commits into
Conversation
When the `target` property of a Bun.plugin() config object throws during string coercion (e.g. toString() returns an object), the exception was left pending and tripped an assertNoException() in constructEmptyObject(). Also add missing <cassert> include in wtf-bindings.cpp which was relying on transitive includes from other unified-build sources.
|
Updated 9:25 PM PT - May 18th, 2026
❌ @robobun, your commit 661b12d has 1 failures in
🧪 To try this PR locally: bunx bun-pr 31017That installs a local version of the PR into your bun-31017 --bun |
There was a problem hiding this comment.
LGTM — straightforward exception-check fix following the standard JSC pattern, with a regression test.
Extended reasoning...
Overview
This PR fixes a debug-build assertion failure in Bun.plugin() when coercing the target option to a string throws (e.g. toString() returns an object). It adds two RETURN_IF_EXCEPTION(throwScope, {}) checks in setupBunPlugin() (BunPlugin.cpp) — one after targetJSString->value(globalObject) for rope resolution, and one after the toStringOrNull block to catch the nullptr-with-pending-exception case. It also adds a missing <cassert> include in wtf-bindings.cpp (which uses assert() in uv__tty_make_raw) and a regression test in plugins.test.ts.
Security risks
None. The change only adds early-return exception checks on an error path; it does not alter parsing, permissions, or any trust boundary. The added include is a build-hygiene fix.
Level of scrutiny
Low. This is a tiny, mechanical fix that follows the exact RETURN_IF_EXCEPTION idiom already used dozens of times in the same file and throughout the JSC bindings. The placement is correct: toStringOrNull returns nullptr on exception, so the outer check after the if block catches it before constructEmptyObject() asserts. The inner check after value() is the standard guard for rope resolution.
Other factors
The fix is fuzzer-driven with a clear repro, and the new test (propagates exception thrown while coercing 'target' to string) directly exercises the previously-crashing path and asserts a TypeError is thrown. No bugs were flagged by the bug-hunting system, and there are no outstanding reviewer comments.
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
Comment |
There was a problem hiding this comment.
LGTM — straightforward exception-check fix following the existing RETURN_IF_EXCEPTION pattern, with a regression test.
Extended reasoning...
Overview
This PR touches three files: BunPlugin.cpp adds two RETURN_IF_EXCEPTION(throwScope, {}) guards in setupBunPlugin() after toStringOrNull / value(globalObject) so that an exception thrown during target string coercion propagates instead of tripping a debug assertion in constructEmptyObject(). wtf-bindings.cpp adds #include <cassert> for the existing assert(tio != NULL) in uv__tty_make_raw, which was previously relying on a transitive include from its unified-build group. The test file adds a regression test exercising the fuzzer repro (toString() returning an object).
Security risks
None. This only adds early-return exception checks on an error path and a standard-library include. No new inputs are accepted, no auth/crypto/permissions code is touched, and behavior for valid inputs is unchanged.
Level of scrutiny
Low. The RETURN_IF_EXCEPTION macro is the canonical JSC idiom and is already used dozens of times in this same function and file; the two new call sites are placed exactly where JSC convention requires (immediately after the potentially-throwing calls). The <cassert> include is a trivial build-hygiene fix with no runtime effect. The added test directly covers the fixed path.
Other factors
No prior human review comments are outstanding. The duplicate-PR bot flagged overlap with #28369 and #30992 — that's a triage/process matter for maintainers but doesn't affect the correctness of this change. CI reported failures on an earlier commit and a retrigger commit was pushed; the diff itself is unlikely to be the cause given its narrow scope, and CI status is already visible to the author.
|
CI status (build #55946): 71 checks passing. Remaining failures are unrelated to this change:
This PR only adds |
|
Superseded by #31286, which has the same exception-check fix as a minimal diff (no unrelated |
Fuzzer found a debug assertion failure in
Bun.plugin().Repro
Cause
setupBunPlugin()callstargetValue.toStringOrNull(globalObject)to coerce thetargetoption to a string. When coercion throws (e.g.toString()returns an object, producing a "No default value" TypeError),toStringOrNullreturnsnullptrand theifbody is skipped — but the pending exception is never checked before continuing toconstructEmptyObject(), which asserts.Fix
Add
RETURN_IF_EXCEPTIONafter thetoStringOrNullpath (and aftervalue(globalObject)for rope resolution).Also adds a missing
<cassert>include inwtf-bindings.cppthat was relying on transitive includes from other files in its unified-build source group.Fingerprint:
0462f40eaa1971c9