ssg 3 - #22138
ssg 3#22138
Conversation
- fix crash - fix require bug
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
src/bun.js/webcore/Response.zig (1)
444-514: Past review feedback not addressed: redirect implementation still in wrong file.Maintainer feedback from previous reviews explicitly stated this redirect code should be in
BakeResponse.zig, notResponse.zig. While the refactoring separatesconstructRedirectImplfrom the wrapper, the core issue remains: this SSR-specific redirect logic doesn't belong in the base Response implementation.Consider moving
constructRedirectImpland the SSR-awareconstructRedirectwrapper tosrc/bun.js/webcore/BakeResponse.zigas originally requested by the maintainer.Based on past review comments.
src/bun.js/webcore/BakeResponse.zig (2)
21-29: Critical: Multiple issues from past reviews remain unaddressed.Two bugs flagged in previous reviews are still present:
Wrong parameter type:
bake_ssr_has_jsxis declared as*c_intbut should be?*c_intsince the constructor (line 31-48) checks for null and the C++ caller may pass null for function-call form.Missing pointer cast: Return type is
?*anyopaquebut the code returns@as(*Response, ...)without casting to*anyopaque, which is UB across ABIs.Apply this fix:
-pub export fn BakeResponseClass__constructForSSR(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame, bake_ssr_has_jsx: *c_int) callconv(jsc.conv) ?*anyopaque { - return @as(*Response, constructor(globalObject, callFrame, bake_ssr_has_jsx) catch |err| switch (err) { +pub export fn BakeResponseClass__constructForSSR(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame, bake_ssr_has_jsx: ?*c_int) callconv(jsc.conv) ?*anyopaque { + const resp = constructor(globalObject, callFrame, bake_ssr_has_jsx) catch |err| switch (err) { error.JSError => return null, error.OutOfMemory => { globalObject.throwOutOfMemory() catch {}; return null; }, - }); + }; + return @ptrCast(resp); }Based on past review comments.
31-48: Critical: Null-pointer dereference remains unfixed.Lines 37 and 43 unconditionally dereference
bake_ssr_has_jsxwithout checking if it's null. The C++ caller passes null for the function-call form (non-constructor invocation), which will cause a crash.Guard all writes to the optional pointer:
pub fn constructor(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame, bake_ssr_has_jsx: ?*c_int) bun.JSError!*Response { var arguments = callframe.argumentsAsArray(2); + if (bake_ssr_has_jsx) |out| out.* = 0; + // Allow `return new Response(<jsx> ... </jsx>, { ... }` // inside of a react component if (!arguments[0].isUndefinedOrNull() and arguments[0].isObject()) { - bake_ssr_has_jsx.* = 0; if (try arguments[0].isJSXElement(globalThis)) { const vm = globalThis.bunVM(); if (try vm.getDevServerAsyncLocalStorage()) |async_local_storage| { try assertStreamingDisabled(globalThis, async_local_storage, "new Response(<jsx />, { ... })"); } - bake_ssr_has_jsx.* = 1; + if (bake_ssr_has_jsx) |out| out.* = 1; } } return Response.constructor(globalThis, callframe); }Based on past review comments.
🧹 Nitpick comments (1)
src/bun.js/webcore/BakeResponse.zig (1)
128-136: Consider improving error messages for better debugging.While the validation logic is correct (including the callable check on line 131), the error messages could be more specific to help developers understand what went wrong. Previous review feedback suggested clearer messages.
Consider applying these message improvements:
fn assertStreamingDisabled(globalThis: *jsc.JSGlobalObject, async_local_storage: JSValue, display_function: []const u8) bun.JSError!void { - if (async_local_storage.isEmptyOrUndefinedOrNull() or !async_local_storage.isObject()) return globalThis.throwInvalidArguments("store value must be an object", .{}); - const getStoreFn = (try async_local_storage.getPropertyValue(globalThis, "getStore")) orelse return globalThis.throwInvalidArguments("store value must have a \"getStore\" field", .{}); - if (!getStoreFn.isCallable()) return globalThis.throwInvalidArguments("\"getStore\" must be a function", .{}); + if (async_local_storage.isEmptyOrUndefinedOrNull() or !async_local_storage.isObject()) + return globalThis.throwInvalidArguments("AsyncLocalStorage must be an object", .{}); + const getStoreFn = (try async_local_storage.getPropertyValue(globalThis, "getStore")) + orelse return globalThis.throwInvalidArguments("AsyncLocalStorage must have a getStore() function", .{}); + if (!getStoreFn.isCallable()) + return globalThis.throwInvalidArguments("AsyncLocalStorage.getStore must be a function", .{}); const store_value = try getStoreFn.call(globalThis, async_local_storage, &.{}); - const streaming_val = (try store_value.getPropertyValue(globalThis, "streaming")) orelse return globalThis.throwInvalidArguments("store value must have a \"streaming\" field", .{}); + if (store_value.isEmptyOrUndefinedOrNull() or !store_value.isObject()) + return globalThis.throwInvalidArguments("getStore() must return an object", .{}); + const streaming_val = (try store_value.getPropertyValue(globalThis, "streaming")) + orelse return globalThis.throwInvalidArguments("store must have a \"streaming\" field", .{}); if (!streaming_val.isBoolean()) return globalThis.throwInvalidArguments("\"streaming\" field must be a boolean", .{}); if (streaming_val.asBoolean()) return globalThis.throwInvalidArguments("\"{s}\" is not available when `export const streaming = true`", .{display_function}); }Based on past review comments.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
src/bun.js/VirtualMachine.zig(2 hunks)src/bun.js/webcore/BakeResponse.zig(1 hunks)src/bun.js/webcore/Response.zig(5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/**/*.zig
📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)
Implement debug logs in Zig using
const log = bun.Output.scoped(.${SCOPE}, false);and invokinglog("...", .{})
Files:
src/bun.js/webcore/BakeResponse.zigsrc/bun.js/VirtualMachine.zigsrc/bun.js/webcore/Response.zig
**/*.zig
📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)
**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue
**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup
Files:
src/bun.js/webcore/BakeResponse.zigsrc/bun.js/VirtualMachine.zigsrc/bun.js/webcore/Response.zig
src/bun.js/**/*.zig
📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)
src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy
Files:
src/bun.js/webcore/BakeResponse.zigsrc/bun.js/VirtualMachine.zigsrc/bun.js/webcore/Response.zig
🧠 Learnings (2)
📚 Learning: 2025-08-30T00:11:00.890Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-08-30T00:11:00.890Z
Learning: Applies to **/*.zig : Wrap the Bun__<Type>__toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue
Applied to files:
src/bun.js/VirtualMachine.zig
📚 Learning: 2025-08-30T00:13:36.815Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-08-30T00:13:36.815Z
Learning: Applies to src/bun.js/**/*.zig : Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
Applied to files:
src/bun.js/webcore/Response.zig
🔇 Additional comments (1)
src/bun.js/VirtualMachine.zig (1)
192-198: LGTM! Well-structured ALS integration.The extern declaration and wrapper follow Zig/JSC interop patterns correctly. The wrapper appropriately uses
jsc.fromJSHostCallfor error handling and returnsnullwhen the result is empty/undefined/null, providing a clean Zig-facing API for dev-server AsyncLocalStorage retrieval.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/bun.js/bindings/bindings.cpp (1)
2386-2398: Use fully qualified JSType enumerator for consistency and to avoid lookup issues.Other cases in this switch use JSC::JSType::…; switch discriminant is a uint8_t cast of JSType. Prefer qualifying the wrapper case the same way.
Apply this diff:
- case JSDOMWrapperType: { + case JSC::JSType::JSDOMWrapperType: { if (jsDynamicCast<WebCore::JSFetchHeaders*>(cell)) return static_cast<double>(jsCast<WebCore::JSFetchHeaders*>(cell)->wrapped().size());
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
src/ast/visitExpr.zig(1 hunks)src/bun.js/VirtualMachine.zig(2 hunks)src/bun.js/bindings/JSValue.zig(2 hunks)src/bun.js/bindings/ZigGlobalObject.cpp(2 hunks)src/bun.js/bindings/bindings.cpp(6 hunks)test/no-validate-leaksan.txt(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- test/no-validate-leaksan.txt
🚧 Files skipped from review as they are similar to previous changes (3)
- src/ast/visitExpr.zig
- src/bun.js/bindings/ZigGlobalObject.cpp
- src/bun.js/bindings/JSValue.zig
🧰 Additional context used
📓 Path-based instructions (7)
src/**/*.zig
📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)
Implement debug logs in Zig using
const log = bun.Output.scoped(.${SCOPE}, false);and invokinglog("...", .{})
Files:
src/bun.js/VirtualMachine.zig
**/*.zig
📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)
**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue
**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup
Files:
src/bun.js/VirtualMachine.zig
src/bun.js/**/*.zig
📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)
src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy
Files:
src/bun.js/VirtualMachine.zig
**/*.{cpp,h}
📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)
**/*.{cpp,h}: When exposing a JS class with public Constructor and Prototype, define three C++ types: class Foo : public JSC::DestructibleObject (if it has C++ fields), class FooPrototype : public JSC::JSNonFinalObject, and class FooConstructor : public JSC::InternalFunction
If the class has C++ data members, inherit from JSC::DestructibleObject and provide proper destruction; if it has no C++ fields (only JS properties), avoid a class and use JSC::constructEmptyObject(vm, structure) with putDirectOffset
Prefer placing the subspaceFor implementation in the .cpp file rather than the header when possible
Files:
src/bun.js/bindings/bindings.cpp
**/*.cpp
📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)
**/*.cpp: Include "root.h" at the top of C++ binding files to satisfy lints
Define prototype properties using a const HashTableValue array and declare accessors/functions with JSC_DECLARE_* macros
Prototype classes should subclass JSC::JSNonFinalObject, provide create/createStructure, DECLARE_INFO, finishCreation that reifies static properties, and set mayBePrototype on the Structure
Custom getters should use JSC_DEFINE_CUSTOM_GETTER, jsDynamicCast to validate this, and throwThisTypeError on mismatch
Custom setters should use JSC_DEFINE_CUSTOM_SETTER, validate this via jsDynamicCast, and store via WriteBarrier/set semantics
Prototype functions should use JSC_DEFINE_HOST_FUNCTION, validate this with jsDynamicCast, and return encoded JSValue
Constructors should subclass JSC::InternalFunction, return internalFunctionSpace in subspaceFor, set the prototype property as non-configurable/non-writable, and provide create/createStructure
Provide a setup function that builds the Prototype, Constructor, and Structure, and assigns them to the LazyClassStructure initializer
Use the cached Structure via globalObject->m_.get(globalObject) when constructing instances
Expose constructors to Zig via an extern "C" function that returns the constructor from the LazyClassStructure
Provide an extern "C" Bun____toJS function that creates an instance using the cached Structure and returns an EncodedJSValue
Files:
src/bun.js/bindings/bindings.cpp
**/*.{cpp,cc,cxx,h,hpp,hxx}
📄 CodeRabbit inference engine (CLAUDE.md)
Format C/C++ sources/headers with clang-format (bun run clang-format)
Files:
src/bun.js/bindings/bindings.cpp
src/bun.js/bindings/**/*.cpp
📄 CodeRabbit inference engine (CLAUDE.md)
src/bun.js/bindings/**/*.cpp: For JS classes with a public constructor, implement Foo, FooPrototype, and FooConstructor (JSC patterns)
Define class properties using HashTableValue arrays in JSC bindings
Add iso subspaces for classes with C++ fields in JSC bindings
Cache structures in ZigGlobalObject for JSC-bound classes
Files:
src/bun.js/bindings/bindings.cpp
🧠 Learnings (4)
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Cache structures in ZigGlobalObject for JSC-bound classes
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-08-30T00:13:36.815Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-08-30T00:13:36.815Z
Learning: Applies to src/bun.js/bindings/generated_classes_list.zig : Update src/bun.js/bindings/generated_classes_list.zig to include new classes
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-08-30T00:11:00.890Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/javascriptcore-class.mdc:0-0
Timestamp: 2025-08-30T00:11:00.890Z
Learning: Applies to **/*.cpp : Provide an extern "C" Bun__<Type>__toJS function that creates an instance using the cached Structure and returns an EncodedJSValue
Applied to files:
src/bun.js/bindings/bindings.cpp
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to src/bun.js/bindings/**/*.cpp : Define class properties using HashTableValue arrays in JSC bindings
Applied to files:
src/bun.js/bindings/bindings.cpp
🧬 Code graph analysis (1)
src/bun.js/bindings/bindings.cpp (1)
src/bun.js/bindings/JSDOMExceptionHandling.h (1)
propagateException(86-90)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Format
🔇 Additional comments (5)
src/bun.js/VirtualMachine.zig (2)
192-198: LGTM! Clean ALS interop implementation.The extern declaration and Zig wrapper follow best practices:
- Proper error union return type for JS exception integration
- Correct use of
jsc.fromJSHostCallfor C++ interop- Appropriate null-checking for empty/undefined/null values
- Aligns with coding guidelines for Zig bindings
845-847: Verify shutdown sequence implications.The commented-out
eventLoop().tick()call prevents processing pending event loop tasks during VM exit. While the comment explains this causes 50+ test failures, this workaround may have implications:
- Pending async operations may not complete
- Resources held by queued tasks may not be properly released
- Deferred cleanup handlers might not execute
Given the PR is already experiencing test failures (per reviewer comments), ensure this change doesn't introduce additional shutdown-related issues in production scenarios, especially for long-running server processes with the new SSR/Bake integration.
Consider opening an issue to track re-enabling this call once the underlying test issues are resolved, as proper event loop draining during shutdown is generally important for cleanup.
src/bun.js/bindings/bindings.cpp (3)
32-32: Includes look good.root.h is present, and adding WebCoreJSBuiltins.h/Strong.h is fine for builtin names and JSC Strong usage. No issues.
Also applies to: 63-63
2005-2025: Native FetchHeaders creation path is correct.
- Returns a native WebCore::FetchHeaders* as expected by Zig callers.
- Handles exceptions via propagateException + deref on failure. LGTM.
6044-6045: Style-only change.Brace repositioning is fine; no behavioral impact.
| JSFetchHeaders* fetchHeaders = jsCast<JSFetchHeaders*>(value); | ||
| fetchHeaders->computeMemoryCost(); | ||
| return JSC::JSValue::encode(value); | ||
| return JSC::JSValue::encode(fetchHeaders); |
There was a problem hiding this comment.
Bug: returning the wrong value (encodes JSFetchHeaders instead of the JSValue).*
Return should encode the JSValue you created (variable “value”), not the JSFetchHeaders* pointer. Use encode(value) for correctness and consistency with neighboring helpers.
Apply this diff:
- return JSC::JSValue::encode(fetchHeaders);
+ return JSC::JSValue::encode(value);🤖 Prompt for AI Agents
In src/bun.js/bindings/bindings.cpp around line 2046, the function currently
returns JSC::JSValue::encode(fetchHeaders) which encodes the JSFetchHeaders*
pointer instead of the JSValue you constructed; change the return to encode the
JSValue variable (value) — i.e., return JSC::JSValue::encode(value) — so the
function returns the actual JSValue as done in neighboring helpers, ensuring
correct encoding and type safety.
|
We will have something like cache invalidation for static pages? |
|
|
…wn (#34035) Fixes `test/bake/dev/request-cookies.test.ts` going red on the `debian 13 x64-asan` lane (seen in [build 72183](https://buildkite.com/bun/bun/builds/72183#019f55d5-6839-41cf-b0f5-3c56ada43ef9) and [build 71964](https://buildkite.com/bun/bun/builds/71964)): ``` dev| ==1715==ERROR: AddressSanitizer: SEGV on unknown address 0x000000007490 error: DevServer panicked at gracefulExit (test/bake/bake-harness.ts:614:17) ✗ DEV:request-cookies-1: request.cookies.get() basic functionality ``` ### Cause `~DevServerSourceProvider` held a raw `Zig::GlobalObject*` and called `m_globalObject->bunVM()` to reach `Bun__removeDevServerSourceProvider`. Under `BUN_DESTRUCT_VM_ON_EXIT=1` (set by the CI runner for the asan lane), the harness's `process.exit(0)` runs `Zig__GlobalObject__destructOnExit`, which does `gcUnprotect(globalObject)` then `collectNow(Sync, Full)` then two `vm.derefSuppressingSaferCPPChecking()`. The global object cell is swept during `collectNow`, but the provider's last `Ref` is only released later from `~CodeCache` inside `~JSC::VM`, so the destructor read `m_bunVM` out of a freed cell. With bmalloc the freed cell usually still holds the old value and the read happens to work, which is why this was ~0.5% in CI and never reproduced locally. When the memory is reused with a zero at that offset the Rust side receives a null `VirtualMachine*` and the next access is `(null)->source_mappings.mutex`, which lands at exactly 0x7490. Deterministic ASAN backtrace with `Malloc=1`: ``` ==79839==ERROR: AddressSanitizer: heap-use-after-free ... #0 Zig::GlobalObject::bunVM() const ZigGlobalObject.h:353 #1 Bake::DevServerSourceProvider::~DevServerSourceProvider() DevServerSourceProvider.h:65 ... #7 JSC::SourceCodeKey::~SourceCodeKey() #12 JSC::CodeCacheMap::~CodeCacheMap() #16 JSC::VM::~VM() #18 Zig__GlobalObject__destructOnExit ZigGlobalObject.cpp:4049 #19 VirtualMachine::global_exit VirtualMachine.rs:1603 #20 Bun__Process__exit ``` ### Fix Store the Rust `VirtualMachine*` directly (`void* m_bunVM`), captured in `create()`, so the destructor no longer indirects through a GC cell. This mirrors `Zig::SourceProvider`, which already stores `m_bunVM` for the same reason. The Rust `VirtualMachine` outlives every GC cell (step 10 of `global_exit` is `self.destroy()`, after `destructOnExit` has finished). ### Verification New ASAN-only case in `test/bake/dev/server-sourcemap.test.ts` runs the dev server with `Malloc=1` + `BUN_DESTRUCT_VM_ON_EXIT=1` so ASAN poisons the swept global-object cell, making the UAF deterministic. Added an `env` option to the `devTest` harness so the test can set those for the spawned dev server. ``` # fail-before (src/ stashed) SUMMARY: AddressSanitizer: heap-use-after-free ZigGlobalObject.h:353:48 in Zig::GlobalObject::bunVM() const (fail) DEV:server-sourcemap-5: DevServerSourceProvider destructor does not touch the swept global object on process exit # pass-after (pass) DEV:server-sourcemap-5: DevServerSourceProvider destructor does not touch the swept global object on process exit ``` `test/bake/dev/server-sourcemap.test.ts` (5 tests) and `test/bake/dev/request-cookies.test.ts` (2 tests) are green. `request-cookies.test.ts` now also passes under the full CI LeakSan config (`BUN_DESTRUCT_VM_ON_EXIT=1` + `detect_leaks=1`). The bug is from a89e61f (#22138), which introduced `DevServerSourceProvider` with the raw global-object pointer. <!-- robobun:evidence:begin --> --- **[review]** gate passed · iteration 1 · 3 files touched <details><summary>fails on main (without fix)</summary> ```console ASAN without fix: 1 FAILED $ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/bake/dev/request-cookies.test.ts test/bake/dev/server-sourcemap.test.ts info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05) info: component rust-src is up to date info: checking for self-update (current version: 1.29.0) bun test v1.4.0 (722d6f0) test/bake/dev/server-sourcemap.test.ts: Dev server testing directory: /tmp/bun-dev-test-tI2Y82 bun add v1.4.0 (722d6f0) Resolving dependencies Resolved, downloaded and extracted [2] Saved lockfile installed react@0.0.0-experimental-603e6108-20241029 installed react-dom@0.0.0-experimental-603e6108-20241029 installed react-server-dom-bun@0.0.0-experimental-603e6108-20241029 installed react-refresh@0.0.0-experimental-603e6108-20241029 6 packages installed [462.00ms] bun install v1.4.0 (722d6f0) Checked 6 installs across 7 packages (no changes) [167.00ms] �[0;30mdev|�[0m Started development server: http://localhost:37377 �[0;30mdev|�[0m �[32mBundled page in 2125ms�[0m�[2m:�[0 ... (truncated) release without fix: all passed bun test v1.4.0-canary.1 (1498d7b) test/bake/dev/server-sourcemap.test.ts: Dev server testing directory: /tmp/bun-dev-test-7LPeWv bun add v1.4.0-canary.1 (1498d7b) Resolving dependencies Resolved, downloaded and extracted [0] Saved lockfile installed react@0.0.0-experimental-603e6108-20241029 installed react-dom@0.0.0-experimental-603e6108-20241029 installed react-server-dom-bun@0.0.0-experimental-603e6108-20241029 installed react-refresh@0.0.0-experimental-603e6108-20241029 6 packages installed [9.00ms] bun install v1.4.0-canary.1 (1498d7b) Checked 6 installs across 7 packages (no changes) [0.00ms] �[0;30mdev|�[0m Started development server: http://localhost:43275 �[0;30mdev|�[0m �[32mBundled page in 47ms�[0m�[2m:�[0m pages/[...slug].tsx �[2m+ 2 more�[0m �[0;30mdev|�[0m �[0m�[1m1 |�[0m �[0m�[35mexport�[0m �[0m�[35mdefault�[0m �[0m�[35masync�[0m �[0m�[35mfunction�[0m MyPage(params) { �[0;30mdev|�[0m �[0m�[1m2 |�[0m myFunc()�[0m�[2m;�[0m �[0;30mdev|�[0m �[0m�[1m3 |�[0m �[0m�[35mreturn�[0m �[0m<�[0mh1>{JSON�[0m�[3m�[1m.stringify�[0m(params)}�[0m<�[0m/h1>�[0m�[2m;�[0m �[0;30mdev|�[0m �[0m�[1m4 |�[0m } �[0;30mdev|�[0m �[0m�[1m5 |�[0m �[0;30mdev|�[0m �[0m� ... (truncated) ``` </details> <details><summary>passes on PR (with fix)</summary> ```console ASAN with fix: all passed $ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/bake/dev/request-cookies.test.ts test/bake/dev/server-sourcemap.test.ts info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05) info: component rust-src is up to date info: checking for self-update (current version: 1.29.0) bun test v1.4.0 (722d6f0) test/bake/dev/server-sourcemap.test.ts: Dev server testing directory: /tmp/bun-dev-test-dkR1se bun add v1.4.0 (722d6f0) Resolving dependencies Resolved, downloaded and extracted [0] Saved lockfile installed react@0.0.0-experimental-603e6108-20241029 installed react-dom@0.0.0-experimental-603e6108-20241029 installed react-server-dom-bun@0.0.0-experimental-603e6108-20241029 installed react-refresh@0.0.0-experimental-603e6108-20241029 6 packages installed [119.00ms] bun install v1.4.0 (722d6f0) Checked 6 installs across 7 packages (no changes) [97.00ms] �[0;30mdev|�[0m Started development server: http://localhost:44249 �[0;30mdev|�[0m �[32mBundled page in 2351ms�[0m�[2m:�[0m ... (truncated) release with fix: all passed $ bun scripts/build.ts --profile=release info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05) info: component rust-src is up to date info: checking for self-update (current version: 1.29.0) [configured] bun-profile → bun (stripped) in 690ms (unchanged) ninja: Entering directory `/workspace/bun/build/release' [0/6] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu) info: syncing channel updates for nightly-2026-05-06-x86_64-unknown-linux-gnu info: latest update on 2026-05-06 for version 1.97.0-nightly (e95e73209 2026-05-05) info: component rust-src is up to date info: component rust-std is up to date nightly-2026-05-06-x86_64-unknown-linux-gnu unchanged - rustc 1.97.0-nightly (e95e73209 2026-05-05) info: checking for self-update (current version: 1.29.0) �[1m�[92m Compiling�[0m bun_core v0.0.0 (/workspace/bun/src/bun_core) �[1m�[92m Compiling�[0m bun_errno v0.0.0 (/workspace/bun/src/errno) �[1m�[92m Compiling�[0m bun_ptr v0.0.0 (/workspace/bun/src/ptr) �[1m�[92m Compiling�[0m bun_boringssl_sys v0.0.0 (/workspace/bun/src/boringssl ... (truncated) ``` </details> <details><summary>diff hotspot</summary> ``` src/runtime/bake/DevServerSourceProvider.h | 13 +++++++----- test/bake/bake-harness.ts | 5 +++++ test/bake/dev/server-sourcemap.test.ts | 34 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) ``` </details> **gate history** · 1 passed · 0 rejected · iteration 1 <details><summary>evidence per changed file</summary> ``` file reads edits tests src/runtime/bake/DevServerSourceProvider.h 1 2 0 test/bake/bake-harness.ts 8 2 0 test/bake/dev/server-sourcemap.test.ts 1 4 0 ``` </details> <!-- robobun:evidence:end -->
What does this PR do?
Fixes a crash related to the dev server overwriting the uws user context
pointer when setting abort callback.
Adds support for
return new Response(<jsx />, { ... })andreturn Response.render(...)andreturn Response.redirect(...):SSRResponseclass to handle this (seeJSBakeResponse.{h,cpp})SSRResponseis designed to "fake" being a React componentsrc/js/builtins/BakeSSRResponse.tsdefines awrapComponentfunction which wrapsthe passed in component (when doing
new Response(<jsx />, ...)). It doesthis to throw an error (in redirect()/render() case) or return the
component.
BakeAdditionsToGlobalstruct which contains some propertiesneeded for this
$$typeof), the rationale behind this is that we couldn't usestructure->addPropertyTransitionbecause JSBakeResponse is not a finalJSObject.
Response -> Bun.SSRResponse(seesrc/ast/P.zigandsrc/ast/visitExpr.zig)Render: struct { path: []const u8 })return Response.render(...)Enables server-side sourcemaps for the dev server:
DevServerSourceProvider.{h,cpp})There are numerous other stuff:
appconfiguration from Bun.serve(...)"use client";components workrequire(...)in dev serverfindSourceMappingURL(...)to usestd.mem.lastIndexOf(...)becausethe sourcemap that should be used is the last one anyway