Skip to content

Conversation

@robobun
Copy link
Collaborator

@robobun robobun commented Nov 24, 2025

Summary

  • Fix a crash (UBSAN: null pointer reference) when creating a CookieMap from an object with symbol properties
  • Skip symbol properties during iteration since they cannot be used as valid cookie names

Test plan

  • Added regression test test/regression/issue/ENG-21750.test.ts
  • Ran all cookie tests: 145 tests pass

Fixes: ENG-21750

🤖 Generated with Claude Code

@linear
Copy link

linear bot commented Nov 24, 2025

@robobun
Copy link
Collaborator Author

robobun commented Nov 24, 2025

Updated 7:58 PM PT - Nov 23rd, 2025

❌ Your commit c251c72a has 5 failures in Build #32297 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 25010

That installs a local version of the PR into your bun-25010 executable, so you can run:

bun-25010 --bun

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 24, 2025

Walkthrough

Use identifierToUSVString when deriving property keys for CookieMap construction, add an exception check after conversion, and use the converted key string when setting records. Add regression tests constructing Bun.CookieMap from objects with symbol properties and numeric-string keys to prevent crashes and validate string-key behavior.

Changes

Cohort / File(s) Summary
JSCookieMap key conversion & exception guard
src/bun.js/bindings/webcore/JSCookieMap.cpp
Replace propertyName.string() with identifierToUSVString result when building key strings; add RETURN_IF_EXCEPTION after conversion; use the converted keyStr when calling record.set.
Regression tests for CookieMap construction
test/regression/issue/ENG-21750.test.ts
Add tests constructing Bun.CookieMap with objects containing symbol properties and numeric-string keys ("1", "2", "123"), asserting no crash and that string keys are retrievable.

Suggested reviewers

  • nektro
  • pfgithub

Pre-merge checks

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main fix: preventing crashes when CookieMap constructor encounters symbol properties.
Description check ✅ Passed The description covers what the PR does and test verification, matching the template structure with sufficient detail about the fix and test results.
Linked Issues check ✅ Passed The PR successfully addresses ENG-21750 by fixing the null pointer crash, implementing symbol property skipping, and adding regression tests as required.
Out of Scope Changes check ✅ Passed All changes are narrowly scoped to fixing the CookieMap constructor crash and adding related regression tests; no extraneous modifications detected.

📜 Recent 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 ba24636 and c251c72.

📒 Files selected for processing (2)
  • src/bun.js/bindings/webcore/JSCookieMap.cpp (1 hunks)
  • test/regression/issue/ENG-21750.test.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (10)
📚 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/webcore/JSCookieMap.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/webcore/JSCookieMap.cpp
📚 Learning: 2025-10-25T17:20:19.041Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 24063
File: test/js/bun/telemetry/server-header-injection.test.ts:5-20
Timestamp: 2025-10-25T17:20:19.041Z
Learning: In the Bun telemetry codebase, tests are organized into two distinct layers: (1) Internal API tests in test/js/bun/telemetry/ use numeric InstrumentKind enum values to test Zig↔JS injection points and low-level integration; (2) Public API tests in packages/bun-otel/test/ use string InstrumentKind values ("http", "fetch", etc.) to test the public-facing BunSDK and instrumentation APIs. This separation allows internal tests to use efficient numeric enums for refactoring flexibility while the public API maintains a developer-friendly string-based interface.

Applied to files:

  • test/regression/issue/ENG-21750.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/ENG-21750.test.ts
📚 Learning: 2025-10-19T02:44:46.354Z
Learnt from: theshadow27
Repo: oven-sh/bun PR: 23798
File: packages/bun-otel/context-propagation.test.ts:1-1
Timestamp: 2025-10-19T02:44:46.354Z
Learning: In the Bun repository, standalone packages under packages/ (e.g., bun-vscode, bun-inspector-protocol, bun-plugin-yaml, bun-plugin-svelte, bun-debug-adapter-protocol, bun-otel) co-locate their tests with package source code using *.test.ts files. This follows standard npm/monorepo patterns. The test/ directory hierarchy (test/js/bun/, test/cli/, test/js/node/) is reserved for testing Bun's core runtime APIs and built-in functionality, not standalone packages.

Applied to files:

  • test/regression/issue/ENG-21750.test.ts
📚 Learning: 2025-09-20T00:58:38.042Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:561-564
Timestamp: 2025-09-20T00:58:38.042Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods (like ctx.redis.set(), ctx.redis.unsubscribe(), etc.) - Bun's Redis client implementation differs from Node.js and can throw synchronously even for async methods. The maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/regression/issue/ENG-21750.test.ts
📚 Learning: 2025-09-20T00:57:56.685Z
Learnt from: markovejnovic
Repo: oven-sh/bun PR: 22568
File: test/js/valkey/valkey.test.ts:268-276
Timestamp: 2025-09-20T00:57:56.685Z
Learning: For test/js/valkey/valkey.test.ts, do not comment on synchronous throw assertions for async Redis methods like ctx.redis.set() - the maintainer has explicitly requested to stop looking at this error pattern.

Applied to files:

  • test/regression/issue/ENG-21750.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/ENG-21750.test.ts
📚 Learning: 2025-10-01T22:13:08.081Z
Learnt from: taylordotfish
Repo: oven-sh/bun PR: 23169
File: src/codegen/bindgenv2/internal/base.ts:120-125
Timestamp: 2025-10-01T22:13:08.081Z
Learning: Iterator.some() and other Iterator helper methods (map, filter, etc.) are supported in Bun and modern Node.js (22+) runtimes and can be safely used on string iterators and other iterator objects.

Applied to files:

  • test/regression/issue/ENG-21750.test.ts
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
Repo: oven-sh/bun PR: 22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.

Applied to files:

  • test/regression/issue/ENG-21750.test.ts
🔇 Additional comments (3)
test/regression/issue/ENG-21750.test.ts (2)

5-20: Effective regression test for the crash scenario.

The test correctly verifies that:

  • Construction with symbol-containing objects (Bun, custom object) doesn't crash
  • String properties remain accessible after construction
  • Instance type is correct

Note: A previous review suggested adding an explicit assertion that symbol properties are not retrievable (e.g., expect(cookieMap2.get(Symbol.for("test") as any)).toBeNull()). While this would document the expected behavior more clearly, the current test is sufficient for regression purposes—it confirms the crash is fixed and string properties work correctly.


22-33: Good coverage for numeric string keys.

This test verifies that numeric string properties (which are valid property names in JavaScript) are correctly handled by CookieMap's constructor. The assertions confirm each numeric key maps to its expected value.

src/bun.js/bindings/webcore/JSCookieMap.cpp (1)

167-170: LGTM! Symbol handling is correct by design.

The fix properly converts string property identifiers to USVStrings. Symbols are prevented from reaching identifierToUSVString entirely—PropertyNameMode::Strings with PrivateSymbolMode::Exclude at line 156 filters out symbols during enumeration at the JSC level. Only string-keyed properties enter the loop, so identifierToUSVString receives only string Identifiers, as intended. The exception check handles conversion errors correctly.


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 f31db64 and 9edfdd6.

📒 Files selected for processing (2)
  • src/bun.js/bindings/webcore/JSCookieMap.cpp (1 hunks)
  • test/regression/issue/ENG-21750.test.ts (1 hunks)
🔇 Additional comments (1)
src/bun.js/bindings/webcore/JSCookieMap.cpp (1)

161-163: LGTM! Defensive guard against symbol properties.

The explicit symbol check correctly prevents the crash. Note that line 156 already specifies PropertyNameMode::Strings, which should theoretically filter out symbols. This additional guard serves as a defensive safeguard, which is appropriate given the crash involved undefined behavior.

Comment on lines +1 to +20
import { expect, test } from "bun:test";

// https://linear.app/oven/issue/ENG-21750
// CookieMap constructor should not crash when passed an object with symbol properties
test("CookieMap should handle objects with symbol properties without crashing", () => {
// This should not crash - Bun object has symbol properties
const cookieMap = new Bun.CookieMap(Bun);
expect(cookieMap).toBeInstanceOf(Bun.CookieMap);

// Also test with a custom object that has symbol properties
const obj = {
foo: "bar",
[Symbol.for("test")]: "value",
[Symbol("local")]: "another",
};
const cookieMap2 = new Bun.CookieMap(obj);
expect(cookieMap2).toBeInstanceOf(Bun.CookieMap);
// Symbol properties should be skipped, but string properties should work
expect(cookieMap2.get("foo")).toBe("bar");
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM! Comprehensive regression test.

The test effectively covers both the crash scenario from the bug report (line 7) and a controlled case with explicit symbol properties (lines 11-19). The assertions verify that construction succeeds and string properties remain accessible.

Optional enhancement: Consider adding an explicit assertion that symbol properties are not retrievable, e.g.:

expect(cookieMap2.get(Symbol.for("test") as any)).toBeNull();

This would document the expected behavior more clearly, though the current test is sufficient.

🤖 Prompt for AI Agents
In test/regression/issue/ENG-21750.test.ts around lines 1 to 20, add an explicit
assertion that symbol-keyed properties are not retrievable from the CookieMap to
document expected behavior; update the test to call cookieMap2.get with the
symbol keys used (e.g., Symbol.for("test") and Symbol("local")) and assert they
return null/undefined (use the same null/undefined expectation style as other
tests), keeping the existing assertions intact.

@robobun robobun force-pushed the claude/fix-cookiemap-symbol-crash branch from 9edfdd6 to ba24636 Compare November 24, 2025 02:50
When creating a CookieMap from an object, calling propertyName.string()
directly could cause a null pointer reference crash with UBSAN. This
change uses identifierToUSVString() which properly handles the conversion
of property names to strings, following the same pattern used in
JSDOMConvertRecord.h.

Fixes: ENG-21750

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

Co-Authored-By: Claude <[email protected]>
@robobun robobun force-pushed the claude/fix-cookiemap-symbol-crash branch from ba24636 to c251c72 Compare November 24, 2025 03:15
Copy link
Member

Choose a reason for hiding this comment

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

These tests do not appear to reproduce the crash. Make sure the tests crash with production bun (or a debug build of bun without your fix)

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.

3 participants