Skip to content

Conversation

@robobun
Copy link
Collaborator

@robobun robobun commented Nov 29, 2025

Summary

  • Fix crash when accessing Response.json().body after catching a stack overflow exception
  • Add proper exception handling with DECLARE_THROW_SCOPE and RETURN_IF_EXCEPTION to ReadableStream__empty and ReadableStream__used functions

Root Cause

When JavaScript code catches an exception with try/catch, the C++ VM still has the "exception pending" flag set. If a C++ function subsequently calls JavaScript code without explicitly checking/handling the exception state, JavaScriptCore's exception scope asserts: "Unexpected exception observed".

The ReadableStream__empty and ReadableStream__used functions were calling JavaScript functions via JSC::call without proper throw scope handling.

Test plan

  • Added regression test test/regression/issue/response-body-crash-after-stack-overflow.test.ts
  • Verified fix with bun bd test test/regression/issue/response-body-crash-after-stack-overflow.test.ts

Fixes: ENG-23921

🤖 Generated with Claude Code

… ReadableStream__used

When accessing Response.json().body after catching a stack overflow exception,
the pending exception state was not being properly handled in the C++ bindings.
This caused a debug assertion failure: "Unexpected exception observed".

The fix adds proper exception handling using DECLARE_THROW_SCOPE and
RETURN_IF_EXCEPTION to both ReadableStream__empty and ReadableStream__used
functions.

Fixes: ENG-23921

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@linear
Copy link

linear bot commented Nov 29, 2025

@robobun
Copy link
Collaborator Author

robobun commented Nov 29, 2025

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 29, 2025

Walkthrough

Adds explicit exception handling in ReadableStream creation routines by introducing throw scopes and exception checks. Previously uncaught exceptions during ReadableStream.create could cause crashes. A regression test validates that accessing Response.json().body after a stack overflow does not crash.

Changes

Cohort / File(s) Summary
ReadableStream exception handling
src/bun.js/bindings/bindings.cpp
Adds DECLARE_THROW_SCOPE and RETURN_IF_EXCEPTION checks in ReadableStream__empty and ReadableStream__used functions to properly handle exceptions during ReadableStream.create invocation
Stack overflow regression test
test/regression/issue/response-body-crash-after-stack-overflow.test.ts
Adds test case verifying that accessing Response.json().body after catching a stack overflow exception does not crash

Possibly related PRs

Suggested reviewers

  • Jarred-Sumner
  • dylan-conway
  • cirospaciari

Pre-merge checks

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing exception handling in two specific ReadableStream C++ functions to prevent crashes.
Description check ✅ Passed The description covers both required template sections with comprehensive details about what was changed and how it was verified.
Linked Issues check ✅ Passed The PR successfully addresses the crash objective from ENG-23921 by adding exception handling to prevent JavaScriptCore assertion failures during Response.json().body access.
Out of Scope Changes check ✅ Passed All changes are directly focused on fixing the crash: C++ exception handling improvements and a targeted regression test validating the specific scenario.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 56da7c4 and bc72951.

📒 Files selected for processing (2)
  • src/bun.js/bindings/bindings.cpp (1 hunks)
  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
test/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

test/**/*.{js,ts,jsx,tsx}: Write tests as JavaScript and TypeScript files using Jest-style APIs (test, describe, expect) and import from bun:test
Use test.each and data-driven tests to reduce boilerplate when testing multiple similar cases

Files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
test/regression/issue/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

When a test is for a specific numbered GitHub Issue, place it in test/regression/issue/${issueNumber}.test.ts with a REAL issue number, not a placeholder

Files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.{ts,tsx}: For single-file tests, prefer using -e flag over tempDir
For multi-file tests, prefer using tempDir from harness and Bun.spawn over other temporary directory creation methods
Always use port: 0 for network tests and do not hardcode ports or use custom random port number functions
Use normalizeBunSnapshot to normalize snapshot output of tests
Never write tests that check for no 'panic' or 'uncaught exception' or similar in the test output - that is NOT a valid test
Use tempDir from harness to create temporary directories, do not use tmpdirSync or fs.mkdtempSync
When spawning processes in tests, check stdout/stderr expectations BEFORE checking exit code to get more useful error messages on test failure
Do not write flaky tests - do not use setTimeout in tests, instead await the condition to be met as you are testing the CONDITION not the TIME PASSING
Verify your test fails with USE_SYSTEM_BUN=1 bun test <file> and passes with bun bd test <file> - your test is NOT VALID if it passes with USE_SYSTEM_BUN=1

Files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.{ts,js,jsx,tsx,mjs,cjs}: Use bun:test with files that end in *.test.{ts,js,jsx,tsx,mjs,cjs}
Do not write flaky tests. Never wait for time to pass in tests; always wait for the condition to be met instead of using an arbitrary amount of time
Never use hardcoded port numbers in tests. Always use port: 0 to get a random port
Prefer concurrent tests over sequential tests using test.concurrent or describe.concurrent when multiple tests spawn processes or write files, unless it's very difficult to make them concurrent
When spawning Bun processes in tests, use bunExe and bunEnv from harness to ensure the same build of Bun is used and debug logging is silenced
Use -e flag for single-file tests when spawning Bun processes
Use tempDir() from harness to create temporary directories with files for multi-file tests instead of creating files manually
Prefer async/await over callbacks in tests
When callbacks must be used and it's just a single callback, use Promise.withResolvers to create a promise that can be resolved or rejected from a callback
Do not set a timeout on tests. Bun already has timeouts
Use Buffer.alloc(count, fill).toString() instead of 'A'.repeat(count) to create repetitive strings in tests, as ''.repeat is very slow in debug JavaScriptCore builds
Use describe blocks for grouping related tests
Always use await using or using to ensure proper resource cleanup in tests for APIs like Bun.listen, Bun.connect, Bun.spawn, Bun.serve, etc
Always check exit codes and test error scenarios in error tests
Use describe.each() for parameterized tests
Use toMatchSnapshot() for snapshot testing
Use beforeAll(), afterEach(), beforeEach() for setup/teardown in tests
Track resources (servers, clients) in arrays for cleanup in afterEach()

Files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
test/regression/issue/**/*.test.ts

📄 CodeRabbit inference engine (test/CLAUDE.md)

Regression tests for specific issues go in /test/regression/issue/${issueNumber}.test.ts. Do not put tests without issue numbers in the regression directory

Files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
src/**/*.{cpp,zig}

📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)

src/**/*.{cpp,zig}: Use bun bd or bun run build:debug to build debug versions for C++ and Zig source files; creates debug build at ./build/debug/bun-debug
Run tests using bun bd test <test-file> with the debug build; never use bun test directly as it will not include your changes
Execute files using bun bd <file> <...args>; never use bun <file> directly as it will not include your changes
Enable debug logs for specific scopes using BUN_DEBUG_$(SCOPE)=1 environment variable
Code generation happens automatically as part of the build process; no manual code generation commands are required

Files:

  • src/bun.js/bindings/bindings.cpp
src/bun.js/bindings/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

src/bun.js/bindings/**/*.cpp: C++ code for JavaScriptCore bindings and Web APIs should be placed in src/bun.js/bindings/*.cpp
When implementing JavaScript classes in C++, create three classes if there's a public constructor: class Foo : public JSC::JSDestructibleObject, class FooPrototype : public JSC::JSNonFinalObject, and class FooConstructor : public JSC::InternalFunction
When implementing JavaScript classes in C++, define properties using HashTableValue arrays and add iso subspaces for classes with C++ fields, caching structures in ZigGlobalObject

Files:

  • src/bun.js/bindings/bindings.cpp
src/**/*.{ts,zig,cpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use absolute paths in file operations

Files:

  • src/bun.js/bindings/bindings.cpp
🧠 Learnings (31)
📓 Common learnings
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>
Learnt from: cirospaciari
Repo: oven-sh/bun PR: 22946
File: test/js/sql/sql.test.ts:195-202
Timestamp: 2025-09-25T22:07:13.851Z
Learning: PR oven-sh/bun#22946: JSON/JSONB result parsing updates (e.g., returning parsed arrays instead of legacy strings) are out of scope for this PR; tests keep current expectations with a TODO. Handle parsing fixes in a separate PR.
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add corresponding test cases to test/v8/v8.test.ts using checkSameOutput() function to compare Node.js and Bun output

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Do not set a timeout on tests. Bun already has timeouts

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:35:08.612Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/dev-server-tests.mdc:0-0
Timestamp: 2025-11-24T18:35:08.612Z
Learning: Applies to test/bake/dev/bundle.test.ts : Organize bundle tests in bundle.test.ts for tests concerning bundling bugs that only occur in DevServer

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-10-18T05:23:24.403Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: test/js/bun/telemetry-server.test.ts:91-100
Timestamp: 2025-10-18T05:23:24.403Z
Learning: In the Bun codebase, telemetry tests (test/js/bun/telemetry-*.test.ts) should focus on telemetry API behavior: configure/disable/isEnabled, callback signatures and invocation, request ID correlation, and error handling. HTTP protocol behaviors like status code normalization (e.g., 200 with empty body → 204) should be tested in HTTP server tests (test/js/bun/http/), not in telemetry tests. Keep separation of concerns: telemetry tests verify the telemetry API contract; HTTP tests verify HTTP semantics.

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to test/js/bun/**/*.test.{ts,tsx} : For Bun-specific API tests, use the `test/js/bun/` directory (for http, crypto, ffi, shell, etc.)

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/regression/issue/**/*.test.ts : Regression tests for specific issues go in `/test/regression/issue/${issueNumber}.test.ts`. Do not put tests without issue numbers in the regression directory

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-03T20:40:59.655Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/bindings/JSValue.zig:545-586
Timestamp: 2025-11-03T20:40:59.655Z
Learning: In Bun's Zig codebase, JSErrors (returned as `bun.JSError!T`) must always be properly handled. Using `catch continue` or `catch { break; }` to silently suppress JSErrors is a bug. Errors should either be explicitly handled or propagated with `try`. This applies to snapshot serializer error handling where Jest's behavior is to throw when serializers throw.

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-10-08T13:48:02.430Z
Learnt from: Jarred-Sumner
Repo: oven-sh/bun PR: 23373
File: test/js/bun/tarball/extract.test.ts:107-111
Timestamp: 2025-10-08T13:48:02.430Z
Learning: In Bun's test runner, use `expect(async () => { await ... }).toThrow()` to assert async rejections. Unlike Jest/Vitest, Bun does not require `await expect(...).rejects.toThrow()` - the async function wrapper with `.toThrow()` is the correct pattern for async error assertions in Bun tests.

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:35:39.205Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Add tests for new Bun runtime functionality

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:36:33.069Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:33.069Z
Learning: Applies to **/*.test.{ts,tsx} : Never write tests that check for no 'panic' or 'uncaught exception' or similar in the test output - that is NOT a valid test

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-10-20T01:38:02.660Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/BunFetchInstrumentation.ts:126-131
Timestamp: 2025-10-20T01:38:02.660Z
Learning: In BunFetchInstrumentation.ts, the force-restore to ORIGINAL_FETCH in the disable() method is intentionally kept (despite appearing unsafe) because it's required for proper test cleanup when instrumentation is repeatedly enabled/disabled. Without it, 15 distributed tracing and context propagation tests fail. Shimmer's unwrap() doesn't reliably restore the original fetch in Bun's globalThis context. The isBunOtelPatched safety check ensures the restore only happens when the current fetch is still ours, preventing clobbering of other tools' wrappers.

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:37:30.259Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: test/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:37:30.259Z
Learning: Applies to test/**/*.test.{ts,js,jsx,tsx,mjs,cjs} : Always use `await using` or `using` to ensure proper resource cleanup in tests for APIs like Bun.listen, Bun.connect, Bun.spawn, Bun.serve, etc

Applied to files:

  • test/regression/issue/response-body-crash-after-stack-overflow.test.ts
📚 Learning: 2025-11-24T18:37:47.899Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/AGENTS.md:0-0
Timestamp: 2025-11-24T18:37:47.899Z
Learning: Applies to src/bun.js/bindings/v8/**/<UNKNOWN> : <UNKNOWN>

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:59:54.571Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h:47-74
Timestamp: 2025-10-01T21:59:54.571Z
Learning: In the new bindings generator (bindgenv2) for `src/bun.js/bindings/webcore/JSDOMConvertEnumeration.h`, the context-aware enumeration conversion overloads intentionally use stricter validation (requiring `value.isString()` without ToString coercion), diverging from Web IDL semantics. This is a design decision documented in comments.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use isolate->currentHandleScope()->createLocal<T>() to create local V8 handles and ensure all V8 values are created within an active handle scope

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-17T20:50:58.644Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23755
File: src/bun.js/api/bun/socket/Handlers.zig:154-159
Timestamp: 2025-10-17T20:50:58.644Z
Learning: In Bun socket configuration error messages (src/bun.js/api/bun/socket/Handlers.zig), use the user-facing JavaScript names "data" and "drain" instead of internal field names "onData" and "onWritable", as these are the names users see in the API according to SocketConfig.bindv2.ts.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/src/symbols.txt : Add symbol names without leading underscore to src/symbols.txt for each new V8 API method

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-10-01T21:49:27.862Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/bun.js/bindings/BunIDLConvert.h:29-42
Timestamp: 2025-10-01T21:49:27.862Z
Learning: In Bun's IDL bindings (src/bun.js/bindings/BunIDLConvert.h), IDLStrictNull intentionally treats both undefined and null as null (using isUndefinedOrNull()), matching WebKit's IDLNull & IDLNullable behavior. This is the correct implementation and should not be changed to only accept null.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.h : Add BUN_EXPORT visibility attribute to all public V8 API functions to ensure proper symbol export across platforms

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Use JSC::WriteBarrier for heap-allocated references in V8 objects and implement visitChildren() for custom heap objects to support garbage collection

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:59.706Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-11-24T18:36:59.706Z
Learning: Applies to src/bun.js/bindings/v8/V8*.cpp : Create V8 class implementations with .cpp extension following the pattern V8ClassName.cpp that include the header, v8_compatibility_assertions.h, use ASSERT_V8_TYPE_LAYOUT_MATCHES macro, and implement methods using isolate->currentHandleScope()->createLocal<T>() for handle creation

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:39.205Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/registering-bun-modules.mdc:0-0
Timestamp: 2025-11-24T18:35:39.205Z
Learning: Applies to **/js_*.zig : Use `bun.JSError!JSValue` for proper error propagation in JavaScript bindings

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : To create JavaScript objects from Zig, implement C++ functions following the `Bun__ClassName__toJS(Zig::GlobalObject*, NativeType*)` convention that construct and return the JavaScript object as an encoded JSValue

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Use `bun.JSError!JSValue` return type for Zig methods and constructors to enable proper error handling and exception propagation

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : Implement getter functions using `JSC_DEFINE_CUSTOM_GETTER` macro, performing type checking with `jsDynamicCast`, throwing errors for type mismatches, and returning encoded JSValue

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : When constructing JavaScript objects, retrieve the structure from the global object using `zigGlobalObject->m_JSX509CertificateClassStructure.get(zigGlobalObject)` or similar pattern

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-03T20:43:06.996Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 24273
File: src/bun.js/test/snapshot.zig:19-19
Timestamp: 2025-11-03T20:43:06.996Z
Learning: In Bun's Zig codebase, when storing JSValue objects in collections like ArrayList, use `jsc.Strong.Optional` (not raw JSValue). When adding values, wrap them with `jsc.Strong.Optional.create(value, globalThis)`. In cleanup code, iterate the collection calling `.deinit()` on each Strong.Optional item before calling `.deinit()` on the ArrayList itself. This pattern automatically handles GC protection. See examples in src/bun.js/test/ScopeFunctions.zig and src/bun.js/node/node_cluster_binding.zig.

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:35:25.883Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-11-24T18:35:25.883Z
Learning: Applies to *.cpp : Implement function definitions using `JSC_DEFINE_HOST_FUNCTION` macro, performing type checking with `jsDynamicCast`, throwing this-type errors when type checking fails, and returning encoded JSValue

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-05T19:49:26.188Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 21728
File: src/valkey/js_valkey_functions.zig:852-867
Timestamp: 2025-09-05T19:49:26.188Z
Learning: In Bun’s Zig code, `.js_undefined` is a valid and preferred JSValue literal for “undefined” (e.g., resolving JSPromise). Do not refactor usages to `jsc.JSValue.jsUndefined()`, especially in src/valkey/js_valkey_functions.zig unsubscribe().

Applied to files:

  • src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-11-24T18:36:08.558Z
Learnt from: CR
Repo: oven-sh/bun PR: 0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-11-24T18:36:08.558Z
Learning: Applies to **/*.zig : Implement getter functions with naming pattern `get<PropertyName>` in Zig that accept `this` and `globalObject` parameters and return `JSC.JSValue`

Applied to files:

  • src/bun.js/bindings/bindings.cpp
🧬 Code graph analysis (2)
test/regression/issue/response-body-crash-after-stack-overflow.test.ts (1)
packages/bun-inspector-protocol/src/protocol/jsc/index.d.ts (1)
  • Response (2793-2806)
src/bun.js/bindings/bindings.cpp (3)
src/bun.js/bindings/JSBuffer.cpp (2)
  • call (320-336)
  • call (320-320)
src/bun.js/bindings/webcore/JSEventEmitter.cpp (2)
  • call (128-157)
  • call (128-128)
src/bun.js/bindings/ProcessBindingTTYWrap.cpp (1)
  • call (407-414)
🔇 Additional comments (1)
src/bun.js/bindings/bindings.cpp (1)

2919-2939: ReadableStream helpers now correctly guard JS calls with ThrowScope

Wrapping the JSC::call in ReadableStream__empty / ReadableStream__used with DECLARE_THROW_SCOPE and RETURN_IF_EXCEPTION is consistent with other bindings and should prevent leaving a pending exception on the VM when these helpers return. This directly addresses the “unexpected exception observed” assertion for the ReadableStream.create path.

No further changes needed here.

Comment on lines +1 to +25
import { test } from "bun:test";

// Fixes: ENG-23921
// Accessing Response.json().body after catching a stack overflow exception
// should not crash the runtime.
test(
"Response.json().body should not crash after catching stack overflow",
() => {
function F0() {
if (!new.target) {
throw "must be called with new";
}
const v3 = this.constructor;
try {
new v3();
} catch (e) {}
// This should not crash - it used to trigger an assertion failure
// due to a pending exception not being properly handled
Response.json().body;
}
// This should not crash
new F0();
},
{ timeout: 60000 },
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Regression test logic is good; drop the explicit timeout and consider naming

The test correctly reproduces the recursive stack overflow and verifies that Response.json().body no longer crashes simply by running the code path.

Two nits:

  1. Per test guidelines, avoid overriding timeouts; the test is synchronous and should not need { timeout: 60000 }. You can simplify to:
-test(
-  "Response.json().body should not crash after catching stack overflow",
-  () => {
+test("Response.json().body should not crash after catching stack overflow", () => {
   // ...
-  },
-  { timeout: 60000 },
-);
+});
  1. The file lives under test/regression/issue/ but the filename is descriptive rather than an issue-number pattern. If your regression suite typically uses numeric identifiers here, consider renaming to include the relevant issue ID for consistency (e.g. incorporating 23921 if that maps to a public issue).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { test } from "bun:test";
// Fixes: ENG-23921
// Accessing Response.json().body after catching a stack overflow exception
// should not crash the runtime.
test(
"Response.json().body should not crash after catching stack overflow",
() => {
function F0() {
if (!new.target) {
throw "must be called with new";
}
const v3 = this.constructor;
try {
new v3();
} catch (e) {}
// This should not crash - it used to trigger an assertion failure
// due to a pending exception not being properly handled
Response.json().body;
}
// This should not crash
new F0();
},
{ timeout: 60000 },
);
import { test } from "bun:test";
// Fixes: ENG-23921
// Accessing Response.json().body after catching a stack overflow exception
// should not crash the runtime.
test("Response.json().body should not crash after catching stack overflow", () => {
function F0() {
if (!new.target) {
throw "must be called with new";
}
const v3 = this.constructor;
try {
new v3();
} catch (e) {}
// This should not crash - it used to trigger an assertion failure
// due to a pending exception not being properly handled
Response.json().body;
}
// This should not crash
new F0();
});
🤖 Prompt for AI Agents
In test/regression/issue/response-body-crash-after-stack-overflow.test.ts around
lines 1-25, remove the unnecessary explicit test timeout object ({ timeout:
60000 }) since the test is synchronous and doesn't need a custom timeout, and
optionally rename the file to follow the regression suite's numeric issue
pattern (e.g., include 23921) if your repo prefers issue-numbered filenames for
consistency; keep the test body otherwise unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants