Skip to content

Validate mock.module() first argument is a string#28518

Merged
Jarred-Sumner merged 2 commits into
mainfrom
farm/ca3e007d/fix-mock-module-non-string-crash
Mar 25, 2026
Merged

Validate mock.module() first argument is a string#28518
Jarred-Sumner merged 2 commits into
mainfrom
farm/ca3e007d/fix-mock-module-non-string-crash

Conversation

@robobun

@robobun robobun commented Mar 24, 2026

Copy link
Copy Markdown
Collaborator

mock.module() calls toString() on its first argument before checking its type, then passes the result through the module resolver. When a non-string value like SharedArrayBuffer is passed, toString() produces "function SharedArrayBuffer() { [native code] }" which the resolver tries to auto-install as a package, crashing because the package manager's logger allocator is uninitialized in this context.

Add an isString() check before the toString() call, matching the validation pattern used by Jest.call() and other Bun APIs.

Crash fingerprint: Address:unknown-crash:bun-debug+0x90074c1

@robobun

robobun commented Mar 24, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 4:02 PM PT - Mar 24th, 2026

@robobun, your commit c4cc290 has 6 failures in Build #41679 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 28518

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

bun-28518 --bun

@coderabbitai

coderabbitai Bot commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 828bef8f-6268-448d-9463-695932c9e75f

📥 Commits

Reviewing files that changed from the base of the PR and between eb9df84 and c4cc290.

📒 Files selected for processing (1)
  • test/js/bun/test/mock/mock-module-non-string.test.ts

Walkthrough

Added a runtime type check in BunPlugin.cpp so mock(module, fn) throws a TypeError if the first argument is not a string; added tests asserting non-string inputs throw and a valid string mock resolves via dynamic import.

Changes

Cohort / File(s) Summary
Plugin: runtime type check
src/bun.js/bindings/BunPlugin.cpp
Added explicit runtime check that callframe->argument(0) is a string before converting to a module specifier; if not, throw TypeError with message mock(module, fn) requires a module name string and return early.
Tests: mock.module validation
test/js/bun/test/mock/mock-module-non-string.test.ts
Added tests that assert mock.module synchronously throws the exact TypeError message for non-string first arguments (examples: SharedArrayBuffer, object literal, number, Symbol) and a test that a valid string mock returns default === 42 on dynamic import.
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description lacks the required template sections (What does this PR do? and How did you verify your code works?) but provides detailed context about the problem, solution, and crash details. Add the PR description template sections: clearly state what the PR does and how the changes were verified (test cases, manual testing, CI status).
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and accurately summarizes the main change: adding validation that the first argument to mock.module() must be a string.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@robobun robobun force-pushed the farm/ca3e007d/fix-mock-module-non-string-crash branch from 79340bd to e9dd4c3 Compare March 24, 2026 18:15
@github-actions

Copy link
Copy Markdown
Contributor

Found 2 issues this PR may fix:

  1. auto-install crashes when an error is thrown #14432 - Auto-install crashes when an error is thrown with logger allocator issues, which matches the crash scenario described in this PR where malformed module identifiers trigger auto-install crashes
  2. Bun crashes when type is missing in import using bun:test #16110 - Bun crashes when type is missing in import using bun:test with Mock types, showing segmentation faults related to mock functionality that could be prevented by better input validation

If this is helpful, consider adding Fixes #<number> to the PR description to auto-close the issue on merge.

🤖 Generated with Claude Code

mock.module() calls toString() on its first argument before checking its
type, then passes the result through the module resolver. When a
non-string value like SharedArrayBuffer is passed, toString() produces
a string like "function SharedArrayBuffer() { [native code] }" which
the resolver tries to auto-install as a package, crashing because the
package manager's logger allocator is uninitialized in this context.

Add an isString() check before the toString() call, matching the
validation pattern used by Jest.call() and other Bun APIs.
@robobun robobun force-pushed the farm/ca3e007d/fix-mock-module-non-string-crash branch from e9dd4c3 to eb9df84 Compare March 24, 2026 18:16

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This PR accidentally deletes the entire BunPlugin.cpp (965 lines) instead of adding an isString() guard — the build will fail at link time due to missing symbols, and the expected error message has no implementation.

Extended reasoning...

Overview

The PR touches two files: it deletes src/bun.js/bindings/BunPlugin.cpp entirely and adds a new test file test/js/bun/test/mock/mock-module-non-string.test.ts. The intent described in the PR description is to add an isString() check inside JSMock__jsModuleMock before the toString() call, but the actual diff shows the entire 965-line file was deleted with no replacement.

Security risks

No security risks in the intended change. The bug being fixed (crash on non-string argument) is a stability issue, not a security vulnerability.

Level of scrutiny

High — this modifies core C++ binding infrastructure for the plugin system, mock module support, and virtual module resolution. These are production-critical code paths used by Bun.plugin(), mock.module(), and the entire onLoad/onResolve plugin mechanism.

Why this cannot be approved

The bug report has been verified: src/bun.js/bindings/BunPlugin.cpp does not exist in the repository, only BunPlugin.h remains. grep finds JSMock__jsModuleMock only in jest.zig (as an extern fn declaration) with no C++ definition anywhere. The error string "mock(module, fn) requires a module name string" that the new test expects is not generated by any code in the codebase. This PR will produce a linker failure with undefined symbols for at minimum: JSMock__jsModuleMock, jsFunctionBunPlugin, jsFunctionBunPluginClear, Bun::runVirtualModule, Bun::createModuleMockStructure, Bun__runOnLoadPlugins, and Bun__runOnResolvePlugins. The fix needs to restore BunPlugin.cpp and add the isString() guard inside JSMock__jsModuleMock.

Comment thread test/js/bun/test/mock/mock-module-non-string.test.ts

@robobun robobun left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The review above was against stale commit 79340bd where a blob upload issue temporarily corrupted the file. That was fixed by force-push to eb9df84 — the current HEAD.

Current diff is correct: BunPlugin.cpp is modified (+5 lines, not deleted), adding the isString() guard inside JSMock__jsModuleMock:

if (!callframe->argument(0).isString()) {
    scope.throwException(lexicalGlobalObject, JSC::createTypeError(lexicalGlobalObject, "mock(module, fn) requires a module name string"_s));
    return {};
}

This is placed before the toString() call, matching the validation pattern in Jest.call().

Comment thread test/js/bun/test/mock/mock-module-non-string.test.ts

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — the isString() guard is correct and the test file now has all required @ts-expect-error annotations.

Extended reasoning...

Overview

This PR modifies src/bun.js/bindings/BunPlugin.cpp to add a 5-line runtime type guard in JSMock__jsModuleMock, and adds a new test file test/js/bun/test/mock/mock-module-non-string.test.ts covering both invalid and valid inputs.

Security risks

None. The change only adds input validation that rejects non-string arguments early, preventing a downstream crash in the module resolver. No auth, crypto, or permission-sensitive code is touched.

Level of scrutiny

Low. The change is a single focused guard matching the established pattern used elsewhere in the same file (e.g., jsFunctionAppendVirtualModulePluginBody already does if (!moduleIdValue.isString())). The fix is surgical and self-contained.

Other factors

Previous review runs flagged two issues: (1) an initial commit that accidentally deleted BunPlugin.cpp entirely, and (2) missing @ts-expect-error annotations on the non-string test calls. Both were corrected in the final commit eb9df84. The current diff is clean: the isString() check is in the right place, the TypeError message matches what the tests assert, and all four non-string calls in the test are properly annotated.

@Jarred-Sumner Jarred-Sumner merged commit 24fa207 into main Mar 25, 2026
56 of 64 checks passed
@Jarred-Sumner Jarred-Sumner deleted the farm/ca3e007d/fix-mock-module-non-string-crash branch March 25, 2026 00:16
structwafel pushed a commit to structwafel/bun that referenced this pull request Apr 25, 2026
`mock.module()` calls `toString()` on its first argument before checking
its type, then passes the result through the module resolver. When a
non-string value like `SharedArrayBuffer` is passed, `toString()`
produces `"function SharedArrayBuffer() { [native code] }"` which the
resolver tries to auto-install as a package, crashing because the
package manager's logger allocator is uninitialized in this context.

Add an `isString()` check before the `toString()` call, matching the
validation pattern used by `Jest.call()` and other Bun APIs.

Crash fingerprint: `Address:unknown-crash:bun-debug+0x90074c1`
xhjkl pushed a commit to xhjkl/bun that referenced this pull request May 14, 2026
`mock.module()` calls `toString()` on its first argument before checking
its type, then passes the result through the module resolver. When a
non-string value like `SharedArrayBuffer` is passed, `toString()`
produces `"function SharedArrayBuffer() { [native code] }"` which the
resolver tries to auto-install as a package, crashing because the
package manager's logger allocator is uninitialized in this context.

Add an `isString()` check before the `toString()` call, matching the
validation pattern used by `Jest.call()` and other Bun APIs.

Crash fingerprint: `Address:unknown-crash:bun-debug+0x90074c1`
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