Fix pending exception when Bun.plugin target coercion throws#31662
Fix pending exception when Bun.plugin target coercion throws#31662robobun wants to merge 1 commit into
Bun.plugin target coercion throws#31662Conversation
setupBunPlugin called toStringOrNull on the plugin's target property but did not check for an exception when the conversion failed (e.g. when Symbol.toPrimitive returns an object). The pending exception was carried into the subsequent call to the plugin's setup() function, which trips ExceptionScope::assertNoException in debug builds. Propagate the exception immediately, matching the pattern used elsewhere in the bindings.
|
Updated 11:10 AM PT - Jun 1st, 2026
❌ @robobun, your commit 243c0c8 has 1 failures in
🧪 To try this PR locally: bunx bun-pr 31662That installs a local version of the PR into your bun-31662 --bun |
|
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 (2)
WalkthroughThis PR refactors exception handling in the plugin target property binding. The ChangesPlugin target conversion exception handling
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
There was a problem hiding this comment.
LGTM — straightforward addition of RETURN_IF_EXCEPTION after toStringOrNull()/value(), with a regression test.
Extended reasoning...
Overview
This PR touches two files: src/jsc/bindings/BunPlugin.cpp (4 lines added in setupBunPlugin) and test/js/bun/plugin/plugins.test.ts (one new regression test). The change pulls targetValue.toStringOrNull(globalObject) out of the if condition and adds RETURN_IF_EXCEPTION(throwScope, {}) after it and after targetJSString->value(globalObject). This is the standard JSC idiom for handling pending exceptions after operations that may invoke user code (here, Symbol.toPrimitive / toString), and matches dozens of identical patterns elsewhere in the bindings.
Security risks
None. The change strictly tightens error handling on an edge-case input — it adds early returns where an exception is already pending, preventing a debug assertion / undefined behavior from continuing with a pending exception. There is no new attack surface, no auth/crypto/permission logic, and no data exposure.
Level of scrutiny
Low. This is a mechanical, well-understood JSC binding pattern (RETURN_IF_EXCEPTION after a fallible JS operation). The diff is tiny and self-contained, the surrounding control flow is unchanged for the non-throwing path, and the fix is verified by a targeted regression test that asserts both that the exception surfaces as a catchable TypeError and that setup() is not invoked.
Other factors
- The bug-hunting system found no issues.
- No CODEOWNERS cover the affected paths.
- No outstanding reviewer comments.
- The added
RETURN_IF_EXCEPTIONafterJSString::value()is technically defensive (rope resolution OOM), but harmless and consistent with the codebase's conventions.
|
Closing as a duplicate of #31286, which fixes the same missing exception check in |
What does this PR do?
Fixes a missing exception check in
setupBunPlugin(Bun.plugin()), found by fuzzing.When the plugin options object has a
targetproperty whose string coercion throws — e.g. an object whoseSymbol.toPrimitivereturns an object —toStringOrNull()returnsnullwith a pending exception. The code treated thenullas "no valid string, skip validation" and continued on to build the builder object and invoke the plugin'ssetup()function with the exception still pending. In debug builds this tripsExceptionScope::assertNoException()and aborts:Repro:
The fix adds
RETURN_IF_EXCEPTIONafter thetoStringOrNull()andJSString::value()calls so the exception propagates to the caller as a normal catchableTypeError, matching the pattern used elsewhere in the bindings (e.g.JSBuffer.cpp,ErrorCode.cpp).How did you verify your code works?
TypeErrorand exits cleanly.test/js/bun/plugin/plugins.test.ts(errors > handles 'target' that throws while being converted to a string). It aborts with the assertion on an unfixed debug build and passes with the fix.bun bd test test/js/bun/plugin/plugins.test.ts,test/js/bun/plugin/plugin-namespace-drive-letter.test.ts, andtest/bundler/bundler_plugin.test.tsall pass.