Commit Graph

14681 Commits

Author SHA1 Message Date
Alistair Smith
b20003779f this is definitely wrong 2026-02-13 18:49:10 -08:00
Alistair Smith
4a9c54d03b fix: safely write usePollingTraps by temporarily unprotecting frozen JSC config page 2026-02-13 17:36:34 -08:00
Alistair Smith
49c2ef2732 fix: remove write to frozen JSC::Options::usePollingTraps (segfault on Linux)
The options page is mprotected read-only after JSC initialization.
Writing to usePollingTraps from Bun__activateRuntimeInspectorMode crashes
with SEGV at offset 0xB34 (the usePollingTraps field offset in the frozen page).
Confirmed via ASAN on Linux aarch64.
2026-02-13 17:16:57 -08:00
Alistair Smith
ee7d7bd99c bisect: WebKit with VMTraps.cpp reverted to PR 159 (test if Debugger.cpp causes crash) 2026-02-13 15:54:23 -08:00
Alistair Smith
0329c4a6a4 fix: use --inspect-port=0 in posix SIGUSR1 tests to avoid port conflicts 2026-02-13 15:07:14 -08:00
Alistair Smith
7214b0475e update WebKit to autobuild-preview-pr-161-d796f228 (fix SignalSender crash on jettisoned code) 2026-02-13 14:10:56 -08:00
Alistair Smith
7c136691a8 refactor(inspector): clean up BunDebugger.cpp naming and duplication
- Rename Bun__setRuntimeInspectorActivated → Bun__activateRuntimeInspectorMode
- Rename Bun__activateInspector → Bun__tryActivateInspector
- Rename Bun__jsDebuggerCallback → Bun__stopTheWorldCallback
- Extract forEachConnection/forEachConnectionForVM iteration helpers
- Merge findVMWithPendingConnections + findVMWithPendingPause → findVMWithPendingWork
- Extract installRunWhilePausedCallback and makeInspectable helpers
- Remove duplicate Bun__tickWhilePaused declarations
- Remove unnecessary messages.clear() before destructor
- Fix stale comment on kMessageDeliveryPause
2026-02-13 13:58:01 -08:00
Alistair Smith
fd1df3f892 fix declare 2026-02-13 13:44:44 -08:00
Alistair Smith
22ca21dce5 cleanup: use Bun__setRuntimeInspectorActivated in STW path too 2026-02-13 13:40:20 -08:00
Alistair Smith
68eeae70f3 fix: set usePollingTraps in event loop activation path to stop SignalSender 2026-02-13 13:38:27 -08:00
Alistair Smith
743b477244 try defer to fix a crash 2026-02-13 13:20:59 -08:00
Alistair Smith
a4c1defe77 remove accidentally committed printer.js 2026-02-13 13:11:21 -08:00
Alistair Smith
7eda29f2d6 fix: cancel VM stop in event loop activation path to prevent residual trap crash
When the event loop path wins the race against STW for inspector activation,
requestResumeAll() doesn't clear the VM's trap bits (world was never stopped).
The residual NeedStopTheWorld trap + poisoned stack limit then crashes when JS
next enters a function. Fix by explicitly calling vm.cancelStop() before
requestResumeAll() on the event loop path.
2026-02-13 13:09:44 -08:00
Alistair Smith
95d01f71c9 Merge branch 'main' into ali/inspector-cdp-pause 2026-02-13 13:02:53 -08:00
Alistair Smith
3680b3887c update WebKit to autobuild-preview-pr-161-aa4d1424 (fix heap walk crash on Linux) 2026-02-13 12:22:25 -08:00
SUZUKI Sosuke
3debd0a2d2 perf(structuredClone): remove unnecessary zero-fill for Int32 and Double array fast paths (#26989)
## What

Replace two-step `Vector<uint8_t>` zero-initialization + `memcpy` with
direct `std::span` copy construction in the `structuredClone` Int32 and
Double array fast paths.

## Why

The previous code allocated a zero-filled buffer and then immediately
overwrote it with `memcpy`. By constructing the `Vector` directly from a
`std::span`, we eliminate the redundant zero-fill and reduce the
operation to a single copy.

### Before
```cpp
Vector<uint8_t> buffer(byteSize, 0);
memcpy(buffer.mutableSpan().data(), data, byteSize);
```

### After
```cpp
Vector<uint8_t> buffer(std::span<const uint8_t> { reinterpret_cast<const uint8_t*>(data), byteSize });
```

## Test

`bun bd test test/js/web/structured-clone-fastpath.test.ts` — 91/92 pass
(1 pre-existing flaky memory test unrelated to this change).

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:50:54 -08:00
Alistair Smith
71cccddf29 fix inspect_port in initBake/second init, reorder exit code assertions in tests 2026-02-12 19:40:09 -08:00
Alistair Smith
11d386c453 address review comments: fix inspect_port ordering, improve error messages, add timeout guards to test loops 2026-02-12 19:10:26 -08:00
Alistair Smith
bff435f3b1 update WebKit to autobuild-preview-pr-161-c7bcfafe (ali/stw3) 2026-02-12 18:49:22 -08:00
Alistair Smith
8bd240b5c2 Merge branch 'main' of github.com:oven-sh/bun into ali/inspector-cdp-pause 2026-02-12 18:14:44 -08:00
Alistair Smith
5bc8d247e0 set JSC::Options::usePollingTraps() = true; when the inspector starts because all js code will get recompiled and polling traps allow us to guarantee hitting STW 2026-02-12 17:57:52 -08:00
robobun
7afead629c fix(linker): defer dynamic import() of unknown node: modules to runtime (#26981)
## Summary

- Defer resolution of dynamic `import()` of unknown `node:` modules
(like `node:sqlite`) to runtime instead of failing at transpile time
- Fix use-after-poison in `addResolveError` by always duping `line_text`
from the source so Location data outlives the arena

Fixes #25707

## Root cause

When a CJS file is `require()`d, Bun's linker eagerly resolves all
import records, including dynamic `import()` expressions. For unknown
`node:` prefixed modules, `whenModuleNotFound` was only deferring
`.require` and `.require_resolve` to runtime — `.dynamic` imports fell
through to the error path, causing the entire `require()` to fail.

This broke Next.js builds with turbopack + `cacheComponents: true` +
Better Auth, because Kysely's dialect detection code uses
`import("node:sqlite")` inside a try/catch that gracefully handles the
module not being available.

Additionally, when the resolve error was generated, the
`Location.line_text` was a slice into arena-allocated source contents.
The arena is reset before `processFetchLog` processes the error, causing
a use-after-poison when `Location.clone` tries to dupe the freed memory.

## Test plan

- [x] New regression test in `test/regression/issue/25707.test.ts` with
3 cases:
- CJS require of file with `import("node:sqlite")` inside try/catch
(turbopack pattern)
  - CJS require of file with bare `import("node:sqlite")` (no try/catch)
  - Runtime error produces correct `ERR_UNKNOWN_BUILTIN_MODULE` code
- [x] Test fails with `USE_SYSTEM_BUN=1` (system bun v1.3.9)
- [x] Test passes with `bun bd test`
- [x] No ASAN use-after-poison crash on debug build


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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-02-12 14:47:31 -08:00
Jarred Sumner
9a72bbfae2 Update CLAUDE.md 2026-02-12 14:25:05 -08:00
robobun
7a801fcf93 fix(ini): prevent OOB read and UB on truncated/invalid UTF-8 in INI parser (#26947)
## Summary

- Fix out-of-bounds read in the INI parser's `prepareStr` function when
a multi-byte UTF-8 lead byte appears at the end of a value with
insufficient continuation bytes
- Fix undefined behavior when bare continuation bytes (0x80-0xBF) cause
`utf8ByteSequenceLength` to return 0, hitting an `unreachable` branch
(UB in ReleaseFast builds)
- Add bounds checking before accessing `val[i+1]`, `val[i+2]`,
`val[i+3]` in both escaped and non-escaped code paths

The vulnerability could be triggered by a crafted `.npmrc` file
containing truncated UTF-8 sequences. In release builds, this could
cause OOB heap reads (potential info leak) or undefined behavior.

## Test plan

- [x] Added 9 tests covering truncated 2/3/4-byte sequences, bare
continuation bytes, and escaped contexts
- [x] All 52 INI parser tests pass (`bun bd test
test/js/bun/ini/ini.test.ts`)
- [x] No regressions in npmrc tests (failures are pre-existing Verdaccio
connectivity issues)

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-12 00:28:44 -08:00
robobun
44541eb574 fix(sql): reject null bytes in connection parameters to prevent protocol injection (#26952)
## Summary

- Reject null bytes in `username`, `password`, `database`, and `path`
connection parameters for both PostgreSQL and MySQL to prevent wire
protocol parameter injection
- Both the Postgres and MySQL wire protocols use null-terminated strings
in their startup/handshake messages, so embedded null bytes in these
fields act as field terminators, allowing injection of arbitrary
protocol parameters (e.g. `search_path` for schema hijacking)
- The fix validates these fields immediately after UTF-8 conversion and
throws `InvalidArguments` error with a clear message if null bytes are
found

## Test plan

- [x] New test
`test/regression/issue/postgres-null-byte-injection.test.ts` verifies:
- Null bytes in username are rejected with an error before any data is
sent
- Null bytes in database are rejected with an error before any data is
sent
- Null bytes in password are rejected with an error before any data is
sent
  - Normal connections without null bytes still work correctly
- [x] Test verified to fail with `USE_SYSTEM_BUN=1` (unfixed bun) and
pass with `bun bd test` (fixed build)
- [x] Existing SQL tests pass (`adapter-env-var-precedence.test.ts`,
`postgres-stringbuilder-assertion-aggressive.test.ts`)

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-12 00:27:00 -08:00
robobun
993be3f931 fix(plugin): set virtualModules to nullptr after delete in clearAll (#26940)
## Summary

- Fix double-free in `Bun.plugin.clearAll()` by setting `virtualModules
= nullptr` after `delete`
- In `jsFunctionBunPluginClear` (`BunPlugin.cpp:956`), `delete
global->onLoadPlugins.virtualModules` freed the pointer without
nullifying it. When the `OnLoad` destructor later runs (during Worker
termination or VM destruction), it checks `if (virtualModules)` — the
dangling non-null pointer passes the check and is deleted again,
corrupting the heap allocator.

## Test plan

- [ ] New test
`test/regression/issue/plugin-clearall-double-free.test.ts` spawns a
subprocess that registers a virtual module, calls
`Bun.plugin.clearAll()`, and exits with `BUN_DESTRUCT_VM_ON_EXIT=1` to
trigger the destructor path
- [ ] Verified the test fails on the system bun (pre-fix) with `pas
panic: deallocation did fail ... Alloc bit not set`
- [ ] Verified the test passes with the debug build (post-fix)
- [ ] Existing plugin tests (`test/js/bun/plugin/plugins.test.ts`) all
pass (29/29)

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-02-11 23:14:43 -08:00
robobun
a68393926b fix(ws): handle fragmented pong frames and validate control frame size (#26944)
## Summary

- Fix WebSocket client pong frame handler to properly handle payloads
split across TCP segments, preventing frame desync that could cause
protocol confusion
- Add missing RFC 6455 Section 5.5 validation: control frame payloads
must not exceed 125 bytes (pong handler lacked this check, unlike ping
and close handlers)

## Details

The pong handler (lines 652-663) had two issues:

1. **Frame desync on fragmented delivery**: When a pong payload was
split across TCP segments (`data.len < receive_body_remain`), the
handler consumed only the available bytes but unconditionally reset
`receive_state = .need_header` and `receive_body_remain = 0`. The
remaining payload bytes in the next TCP delivery were then
misinterpreted as WebSocket frame headers.

2. **Missing payload length validation**: Unlike the ping handler (line
615) and close handler (line 680), the pong handler did not validate the
7-bit payload length against the RFC 6455 limit of 125 bytes for control
frames.

The fix models the pong handler after the existing ping handler pattern:
track partial delivery state with a `pong_received` boolean, buffer
incoming data into `ping_frame_bytes`, and only reset to `need_header`
after the complete payload has been consumed.

## Test plan

- [x] New test `websocket-pong-fragmented.test.ts` verifies:
- Fragmented pong delivery (50-byte payload split into 2+48 bytes) does
not cause frame desync, and a subsequent text frame is received
correctly
- Pong frames with >125 byte payloads are rejected as invalid control
frames
- [x] Test fails with `USE_SYSTEM_BUN=1` (reproduces the bug) and passes
with `bun bd test`
- [x] Existing WebSocket tests pass: `websocket-client.test.ts`,
`websocket-close-fragmented.test.ts`,
`websocket-client-short-read.test.ts`

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 23:12:28 -08:00
robobun
e8a5f23385 fix(s3): reject CRLF characters in header values to prevent header injection (#26942)
## Summary

- Fixes HTTP header injection vulnerability in S3 client where
user-controlled options (`contentDisposition`, `contentEncoding`,
`type`) were passed to HTTP headers without CRLF validation
- Adds input validation at the JS-to-Zig boundary in
`src/s3/credentials.zig` that throws a `TypeError` if `\r` or `\n`
characters are detected
- An attacker could previously inject arbitrary headers (e.g.
`X-Amz-Security-Token`) by embedding `\r\n` in these string fields

## Test plan

- [x] Added `test/regression/issue/s3-header-injection.test.ts` with 6
tests:
  - CRLF in `contentDisposition` throws
  - CRLF in `contentEncoding` throws
  - CRLF in `type` (content-type) throws
  - Lone CR in `contentDisposition` throws
  - Lone LF in `contentDisposition` throws
  - Valid `contentDisposition` without CRLF still works correctly
- [x] Tests fail with `USE_SYSTEM_BUN=1` (confirming vulnerability
exists in current release)
- [x] Tests pass with `bun bd test` (confirming fix works)

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 23:02:39 -08:00
robobun
16b3e7cde7 fix(libarchive): use normalized path in mkdiratZ to prevent directory traversal (#26956)
## Summary

- Fix path traversal vulnerability in tarball directory extraction on
POSIX systems where `mkdiratZ` used the un-normalized `pathname` (raw
from tarball) instead of the normalized `path` variable, allowing `../`
components to escape the extraction root via kernel path resolution
- The Windows directory creation, symlink creation, and file creation
code paths already correctly used the normalized path — only the two
POSIX `mkdiratZ` calls were affected (lines 463 and 469)
- `bun install` is not affected because npm mode skips directory
entries; affected callers include `bun create`, GitHub tarball
extraction, and `compile_target`

## Test plan

- [x] Added regression test that crafts a tarball with
`safe_dir/../../escaped_dir/` directory entry and verifies it cannot
create directories outside the extraction root
- [x] Verified test **fails** with system bun (vulnerable) and
**passes** with debug build (fixed)
- [x] Full `archive.test.ts` suite passes (99/99 tests)
- [x] `symlink-path-traversal.test.ts` continues to pass (3/3 tests)

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 22:47:41 -08:00
robobun
4c32f15339 fix(sql): use constant-time comparison for SCRAM server signature (#26937)
## Summary

- Replace `bun.strings.eqlLong` with BoringSSL's `CRYPTO_memcmp` for
SCRAM-SHA-256 server signature verification in the PostgreSQL client
- The previous comparison (`eqlLong`) returned early on the first
mismatching byte, potentially leaking information about the expected
server signature via timing side-channel
- `CRYPTO_memcmp` is already used elsewhere in the codebase for
constant-time comparisons (CSRF tokens, `crypto.timingSafeEqual`,
KeyObject comparison)

## Test plan

- [x] `bun bd` compiles successfully
- [ ] Existing SCRAM-SHA-256 integration tests in
`test/js/sql/sql.test.ts` pass (require Docker/PostgreSQL)

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 22:45:47 -08:00
robobun
635034ee33 fix(shell): use-after-free in runFromJS when setupIOBeforeRun fails (#26920)
## Summary

- Fixes #26918 — segfault at address `0x28189480080` caused by
use-after-free in the shell interpreter
- When `setupIOBeforeRun()` fails (e.g., stdout handle unavailable on
Windows), the `runFromJS` error path called `deinitFromExec()` which
directly freed the GC-managed interpreter object with
`allocator.destroy(this)`. When the GC later swept and called
`deinitFromFinalizer()` on the already-freed memory, it caused a
segfault.
- Replaced `deinitFromExec()` with `derefRootShellAndIOIfNeeded(true)`
which properly cleans up runtime resources (IO handles, shell
environment) while leaving final object destruction to the GC finalizer
— matching the pattern already used in `finish()`.

## Test plan

- [x] Added regression test in `test/regression/issue/26918.test.ts`
that verifies the shell interpreter handles closed stdout gracefully
without crashing
- [x] Test passes with `bun bd test test/regression/issue/26918.test.ts`
- [ ] The actual crash is primarily reproducible on Windows where stdout
handles can be truly unavailable — CI Windows tests should validate the
fix

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2026-02-11 17:51:10 -08:00
robobun
3e792d0d2e fix(test): write JUnit reporter outfile when --bail triggers early exit (#26852)
## Summary
- When `--bail` caused an early exit after a test failure, the JUnit
reporter output file (`--reporter-outfile`) was never written because
`Global.exit()` was called before the normal completion path
- Extracted the JUnit write logic into a `writeJUnitReportIfNeeded()`
method on `CommandLineReporter` and call it in both bail exit paths
(test failure and unhandled rejection) as well as the normal completion
path

Closes #26851

## Test plan
- [x] Added regression test `test/regression/issue/26851.test.ts` with
two cases:
  - Single failing test file with `--bail` produces JUnit XML output
- Multiple test files where bail triggers on second file still writes
the report
- [x] Verified test fails with system bun (`USE_SYSTEM_BUN=1`)
- [x] Verified test passes with `bun bd test`

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-11 17:41:45 -08:00
Alistair Smith
32abcf8736 some fixes 2026-02-11 17:30:31 -08:00
robobun
b7d505b6c1 deflake: make HMR rapid edits test event-driven (#26890)
## Summary
- Add `expectMessageEventually(value)` to the bake test harness `Client`
class — waits for a specific message to appear, draining any
intermediate messages that arrived before it
- Rewrite "hmr handles rapid consecutive edits" test to use raw
`Bun.write` + sleep for intermediate edits and `expectMessageEventually`
for the final assertion, avoiding flaky failures when HMR batches
updates non-deterministically across platforms

Fixes flaky failure on Windows where an extra "render 10" message
arrived after `expectMessage` consumed its expected messages but before
client disposal.

## Test plan
- [x] `bun bd test test/bake/dev-and-prod.test.ts` — all 12 tests pass
- [x] Ran the specific test multiple times to confirm no flakiness

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

Co-authored-by: Alistair Smith <alistair@anthropic.com>
2026-02-11 16:05:25 -08:00
Alistair Smith
e5089fc1fd try to find a default port with runtime inspector in tests? 2026-02-11 11:34:17 -08:00
Alistair Smith
0d1a98b5e0 revert: restore preview WebKit with breakProgram() (reverts accidental revert)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-11 11:14:38 -08:00
Alistair Smith
005c9184bf revert: use original WebKit version (breakProgram causes test failures) 2026-02-11 11:10:40 -08:00
autofix-ci[bot]
5c165f8ab2 [autofix.ci] apply automated fixes 2026-02-11 07:06:31 +00:00
Dylan Conway
50e478dcdc fix(crypto): correct method and constructor names mangled by number renamer (#26876)
## Problem

The bundler's number renamer was mangling `.name` properties on crypto
class prototype methods and constructors:

- `hash.update.name` → `"update2"` instead of `"update"`
- `verify.verify.name` → `"verify2"` instead of `"verify"`
- `cipher.update.name` → `"update3"` instead of `"update"`
- `crypto.Hash.name` → `"Hash2"` instead of `"Hash"`

### Root causes

1. **Named function expressions on prototypes** collided with other
bindings after scope flattening (e.g. `Verify.prototype.verify =
function verify(...)` collided with the imported `verify`)
2. **Block-scoped constructor declarations** (`Hash`, `Hmac`) got
renamed when the bundler hoisted them out of block scope
3. **Shared function declarations** in the Cipher/Decipher block all got
numeric suffixes (`update3`, `final2`, `setAutoPadding2`, etc.)

## Fix

- Use `Object.assign` with object literals for prototype methods —
object literal property keys correctly infer `.name` and aren't subject
to the renamer
- Remove unnecessary block scopes around `Hash` and `Hmac` constructors
so they stay at module level and don't get renamed
- Inline `Cipheriv` methods and copy references to `Decipheriv`

## Tests

Added comprehensive `.name` tests for all crypto classes: Hash, Hmac,
Sign, Verify, Cipheriv, Decipheriv, DiffieHellman, ECDH, plus factory
functions and constructor names.
2026-02-10 23:06:22 -08:00
robobun
e8f73601c0 fix(compile): use remaining buffer in standalone POSIX write loop (#26882)
## What does this PR do?

Fixes the write loop in `StandaloneModuleGraph.inject()` for POSIX
targets (the `else` branch handling ELF/Linux standalone binaries) to
pass `remain` instead of `bytes` to `Syscall.write()`.

## Problem

The write loop that appends the bundled module graph to the end of the
executable uses a standard partial-write retry pattern, but passes the
full `bytes` buffer on every iteration instead of the remaining portion:

```zig
var remain = bytes;
while (remain.len > 0) {
    switch (Syscall.write(cloned_executable_fd, bytes)) {   // bug: should be 'remain'
        .result => |written| remain = remain[written..],
        ...
    }
}
```

If a partial write occurs, the next iteration re-writes from the start
of the buffer instead of continuing where it left off, corrupting the
output binary. The analogous read loop elsewhere in the same file
already correctly uses `remain`.

## Fix

One-character change: `bytes` → `remain` in the `Syscall.write()` call.

## How did you verify your code works?

- `bun bd` compiles successfully
- `bun bd test test/bundler/bun-build-compile.test.ts` — 4/4 pass

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Alistair Smith <alistair@anthropic.com>
2026-02-10 23:04:46 -08:00
Alistair Smith
8ace3a5e27 make runtime-inspector less flaky 2026-02-10 23:00:29 -08:00
robobun
ba6e84fecd fix(compile): seek to start of file before EXDEV cross-device copy (#26883)
## What does this PR do?

Fixes `bun build --compile` producing an all-zeros binary when the
output directory is on a different filesystem than the temp directory.
This is common in Docker containers, Gitea runners, and other
environments using overlayfs.

## Problem

When `inject()` finishes writing the modified executable to the temp
file, the file descriptor's offset is at EOF. If the subsequent
`renameat()` to the output path fails with `EXDEV` (cross-device — the
temp file and output dir are on different filesystems), the code falls
back to `copyFileZSlowWithHandle()`, which:

1. Calls `fallocate()` to pre-allocate the output file to the correct
size (filled with zeros)
2. Calls `bun.copyFile(in_handle, out_handle)` — but `in_handle`'s
offset is at EOF
3. `copy_file_range` / `sendfile` / `read` all use the current file
offset (EOF), read 0 bytes, and return immediately
4. Result: output file is the correct size but entirely zeros

This explains user reports of `bun build --compile
--target=bun-darwin-arm64` producing invalid binaries that `file`
identifies as "data" rather than a Mach-O executable.

## Fix

Seek the input fd to offset 0 in `copyFileZSlowWithHandle` before
calling `bun.copyFile`.

## How did you verify your code works?

- `bun bd` compiles successfully
- `bun bd test test/bundler/bun-build-compile.test.ts` — 6/6 pass
- Added tests that verify compiled binaries have valid executable
headers and produce correct output
- Manually verified cross-compilation: `bun build --compile
--target=bun-darwin-arm64` produces a valid Mach-O binary

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 22:32:31 -08:00
SUZUKI Sosuke
e29e830a25 perf(path): use pre-built Structure for path.parse() result objects (#26865)
## Summary

Optimize `path.parse()` by caching a pre-built JSC Structure for the
result object. Instead of creating a new empty object and performing 5
`putDirect` calls (each triggering a Structure transition), we now use
`constructEmptyObject` with the cached Structure and write values
directly via `putDirectOffset`.

## What changed

- **`ZigGlobalObject.h/cpp`**: Added `m_pathParsedObjectStructure` as a
`LazyPropertyOfGlobalObject<Structure>` with fixed property offsets for
`{root, dir, base, ext, name}`.
- **`Path.cpp`**: Added `PathParsedObject__create` extern "C" factory
function that constructs the object using the pre-built Structure and
`putDirectOffset`.
- **`path.zig`**: Replaced `toJSObject()` implementation to call the C++
factory function instead of `createEmptyObject` + 5x `.put()`.
- **`bench/snippets/path-parse.mjs`**: Added benchmark for
`path.parse()`.

This follows the same pattern used by `JSSocketAddressDTO` and
`m_jsonlParseResultStructure`.

## Benchmark results (Apple M4 Max)

| Benchmark | Before (1.3.9) | After | Speedup |
|---|---|---|---|
| `posix.parse("/home/user/dir/file.txt")` | 266.71 ns | 119.62 ns |
**2.23x** |
| `posix.parse("/home/user/dir/")` | 239.10 ns | 91.46 ns | **2.61x** |
| `posix.parse("file.txt")` | 232.55 ns | 89.20 ns | **2.61x** |
| `posix.parse("/root")` | 246.75 ns | 92.68 ns | **2.66x** |
| `posix.parse("")` | 152.19 ns | 20.72 ns | **7.34x** |
| `win32.parse("/home/user/dir/file.txt")` | 260.08 ns | 118.12 ns |
**2.20x** |
| `win32.parse("/home/user/dir/")` | 234.35 ns | 93.47 ns | **2.51x** |
| `win32.parse("file.txt")` | 224.19 ns | 80.56 ns | **2.78x** |
| `win32.parse("/root")` | 241.20 ns | 88.23 ns | **2.73x** |
| `win32.parse("")` | 160.39 ns | 24.20 ns | **6.63x** |

**~2.2x–2.8x faster** for typical paths, **~7x faster** for empty
strings.

## GC Safety

- `LazyPropertyOfGlobalObject<Structure>` is automatically visited via
`FOR_EACH_GLOBALOBJECT_GC_MEMBER`.
- JSValues created by `createUTF8ForJS` are protected by JSC's
conservative stack scanning during the factory function call.

## Test

All 116 existing path tests pass (`bun bd test test/js/node/path/`).

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-02-10 22:32:08 -08:00
Alistair Smith
5fc0806f8c cleanup debugger file and tests 2026-02-10 22:14:31 -08:00
Alistair Smith
2df14412e3 simplify the atomics a bunch 2026-02-10 21:39:36 -08:00
Alistair Smith
3ba2cb888a fix the race + some pr review 2026-02-10 21:31:40 -08:00
Alistair Smith
3a6a346438 fix: use WebKit preview build with breakProgram() for reliable while(true) pause
Point to autobuild-preview-pr-159-f611d4a9 which includes the
breakProgram() call in the NeedDebuggerBreak handler, needed to
reliably enter the debugger pause loop from DFG tight loops.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-10 18:16:00 -08:00
Alistair Smith
a54d19e533 fix(test): remove explicit test timeout per test/CLAUDE.md guidelines
Bun's test runner has built-in timeouts, so explicit timeout params
are unnecessary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-10 16:41:18 -08:00
Alistair Smith
7f01e99c55 Merge branch 'main' into ali/inspector-cdp-pause 2026-02-10 16:31:43 -08:00
robobun
4c205486d6 fix(test): update valkey test snapshots for Redis 8 error message format (#26878)
## Summary
- Update inline error snapshots in valkey reliability tests to match
Redis 8's changed error message format
- Redis 8 (`redis:8-alpine` in our test Docker container) no longer
appends `, with args beginning with: ` when an unknown command has no
arguments

## Root cause
Redis commit
[`25f780b6`](25f780b662)
([PR #14690](https://github.com/redis/redis/pull/14690)) changed
`commandCheckExistence()` in `src/server.c` to only append `, with args
beginning with: ` when there are actual arguments (`c->argc >= 2`).
Previously it was always appended, producing a dangling `, with args
beginning with: ` even with zero arguments.

## Changes
- `test/js/valkey/reliability/protocol-handling.test.ts`: Updated
`SYNTAX-ERROR` snapshot (no args case)
- `test/js/valkey/reliability/error-handling.test.ts`: Updated
`undefined` and `123` snapshots (no args cases)

## Test plan
- [ ] Verify `protocol-handling.test.ts` passes in CI (was failing on
every attempt as shown in #26869 / build #36831)
- [ ] Verify `error-handling.test.ts` passes in CI

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

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 16:30:55 -08:00