Commit Graph

8829 Commits

Author SHA1 Message Date
Claude Bot
8136c0614d Add comprehensive documentation to doAccept function
Added detailed doc comment explaining:
- Function purpose: accepts already-open FD and attaches to server
- Parameters: file descriptor number via callframe.argument(0)
- Return behavior: js_undefined on success, throws bun.JSError on error
- Common use cases: systemd socket activation, Unix domain socket FD passing
- Error semantics: all validation checks and preconditions

Documentation follows project style with triple-slash comments and clearly
highlights what callers must provide and what errors to expect.

Addresses CodeRabbit review feedback.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 22:00:41 +00:00
Claude Bot
cab0017920 Use direct argument access instead of array allocation
Replaced callframe.argumentsAsArray(1)[0] with callframe.argument(0)
to avoid unnecessary array allocation. Since we already validate
argumentsCount() >= 1, we can safely use direct argument access.

This is more efficient and follows the validation-then-access pattern
recommended by CodeRabbit.

All 7 tests pass with 281 expect() assertions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 21:51:48 +00:00
Claude Bot
4dfe3d4709 Add argument count validation and remove unreachable check
Addresses CodeRabbit review feedback:

1. Added explicit argument count validation using callframe.argumentsCount()
   before accessing argumentsAsArray(1)[0]. This ensures proper error
   handling when no arguments are provided.

2. Removed unreachable upper bound check (fd > maxInt(u32)). Since fd is
   of type i32, it can never exceed maxInt(u32) (4294967295), making that
   check redundant and unreachable.

The code now properly validates:
- Argument count (must have at least 1 argument)
- Argument type (must be a number)
- FD value (must be >= 0)

All 7 tests pass with 281 expect() assertions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 21:36:34 +00:00
Claude Bot
21c3ee79fa Add FD range validation and improve error message clarity
Addresses CodeRabbit review feedback:

1. Added upper bound validation (maxInt(u32)) before @intCast to prevent
   potential issues with extremely large i32 values

2. Simplified error message to be truthful about what we actually validate
   locally. Changed from claiming to validate "socket FD" and "SSL
   configuration" to simply reporting "Failed to accept file descriptor {d}"

   The actual validation of socket type and SSL compatibility happens in
   the C++ layer (us_socket_from_fd), not in this Zig code. The error
   message now accurately reflects what this function checks.

All 7 tests pass with 281 expect() assertions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 21:21:27 +00:00
Claude Bot
32ad95aa34 Improve error message for server.accept() failures
Enhanced the error message to include:
- The actual file descriptor number that failed
- Guidance on common failure causes (invalid socket FD, SSL mismatch)

This helps users diagnose issues more quickly when accept() fails.

Addresses CodeRabbit review comment.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 21:05:51 +00:00
Claude Bot
33efd885ec Migrate server.accept() to use argumentsAsArray
Replaced .arguments_old() with .argumentsAsArray() to comply with
codebase ban on .arguments_old().

- Simplified argument handling by using argumentsAsArray(1)[0]
- Removed manual length check (argumentsAsArray handles this)
- Clarified SSL documentation wording slightly

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 20:06:52 +00:00
Claude Bot
ab9a588fd1 Add full SSL/TLS support to server.accept()
Implemented complete SSL support following the same pattern used
throughout libuwsockets.cpp:

- Added SSL branch that uses uWS::SSLApp and HttpContext<true>
- Uses HttpResponseData<true> for SSL sockets
- Properly initializes SSL socket extensions with placement new
- Triggers on_open callback for SSL connections
- Updated documentation to reflect SSL/TLS support

Both SSL and non-SSL sockets now work correctly with server.accept().
The implementation follows the exact same pattern as all other
uWebSockets operations in libuwsockets.cpp (get, post, listen, etc).

All 7 tests pass with 281 expect() assertions.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 17:32:10 +00:00
Claude Bot
5e72f1c6c9 Document HttpContext pointer arithmetic technical debt
Added detailed comment explaining why we use pointer arithmetic to
access the private httpContext member of uWS::App:

- uWebSockets is a vendored library, so we can't easily add accessors
- The approach is consistent with patterns in App.h (lines 115, 127, 132)
- The TemplatedApp memory layout (httpContext as first member) is stable
- Similar pointer arithmetic is used elsewhere in libuwsockets.cpp

This addresses the code review suggestion to use an accessor function,
while acknowledging the constraint that modifying the vendored library
is not practical. The comment documents the technical debt for future
maintainers.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 16:53:01 +00:00
Claude Bot
89d967f479 Address CodeRabbit review feedback
1. Remove unused #include <stdio.h> from socket.c
   - stdio.h was added for debug logging but is no longer needed

2. Fix SSL branch in uws_app_accept()
   - SSL/TLS socket acceptance now properly rejects with -1
   - Added comment explaining proper implementation would require
     us_socket_wrap_with_tls() + us_socket_open() for TLS handshake
   - Avoids unsafe construction of TLS HttpResponseData on non-TLS socket

3. Add #include <new> for placement new
   - Required for placement new syntax used in HttpResponseData initialization

4. Update accept() documentation with ownership semantics
   - Clarifies that app takes FD ownership on success
   - Caller retains ownership and must close FD on failure
   - Notes that SSL/TLS is not currently supported

5. Optimize test buffer allocations
   - Large POST body: Use Buffer.alloc(10000, 0x78).toString() instead of "x".repeat(10000)
   - Binary upload: Use Buffer.allocUnsafe(1000) and i & 0xff for faster allocation

All tests still pass (7 pass, 279 expect() calls).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 16:51:41 +00:00
Claude Bot
2a943b9518 Fix server.accept() by properly accessing HttpContext from App
The issue was that server.accept() was casting the uWebSockets App
pointer directly to us_socket_context_t*, but the App is a wrapper that
contains HttpContext as its first member. The HttpContext IS the socket
context, not the App itself.

This caused the event loop file descriptor to be read incorrectly (showing
as 0 instead of the actual epoll FD), which then caused epoll_ctl to fail
with EINVAL when trying to add socket pair file descriptors.

The fix accesses the httpContext pointer (first member of App struct) via
pointer arithmetic, then casts that to us_socket_context_t*. This gives us
the correct socket context with a properly initialized event loop.

All 6 tests now pass, including tests for:
- Basic HTTP request handling
- Multiple requests with Keep-Alive
- Large POST body handling
- Invalid file descriptor handling
- Argument validation

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 16:05:00 +00:00
Claude Bot
01d5f5069b Add server.accept() method to accept file descriptors
Implements server.accept(fd) method that allows accepting a file descriptor
number and integrating it as an HTTP connection to the server. This enables
use cases where file descriptors are obtained externally and need to be
handled by Bun's HTTP server.

Changes:
- Add accept() method to server.classes.ts
- Implement doAccept() in server.zig with FD validation
- Add uws_app_accept() C++ wrapper in libuwsockets.cpp
- Add Zig bindings in App.zig
- Create socket from FD using us_socket_from_fd()
- Initialize HttpResponseData and trigger on_open callback
- Add basic tests in server-accept.test.ts

The method validates the file descriptor, creates a socket from it,
and runs it through the same initialization code path as regular
connections, ensuring proper HTTP request handling.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-16 15:50:23 +00:00
pfg
324c0d1a39 Eliminates special handling for bun:test in the transpiler (#22888)
Eliminates special handling for bun:test in the transpiler
2025-10-14 20:51:34 -07:00
Meghan Denny
0eb470fd88 zig: handle termination exception from promise fulfullment/rejection (#23285) 2025-10-14 19:48:25 -07:00
Meghan Denny
c3bfff58d9 Revert "Add support for localAddress and localPort in TCP connections" (#23675) 2025-10-14 19:46:47 -07:00
Michael H
37ad295114 bun.shell: Add .quiet(boolean) 2025-10-14 17:43:38 -07:00
Jarred Sumner
bad726f943 fix(watcher): handle vim atomic save race on macOS (#23566)
## Summary

Fixes a race condition on macOS where editing the entrypoint with vim's
atomic save causes "Module not found" errors during hot reload.

## Root Cause

On macOS, kqueue watches file descriptors/inodes, not paths. Vim's
atomic save sequence:
1. Rename `a.js` to `a.js~` → kqueue reports `NOTE_RENAME` on watched fd
2. Hot reloader immediately triggers reload
3. New file hasn't been created yet → `ENOENT` error
4. Vim re-creates `a.js`, and writes file contents into it
5. Directory gets `NOTE_WRITE` but file already removed from watchlist

```
rename("a.js", "a.js~")                 = 0
openat(AT_FDCWD, "a.js", O_WRONLY|O_CREAT, 0664) = 3
ftruncate(3, 0)                         = 0
write(3, "foobar\n", 7)                 = 7
close(3)                                = 0
```

This is macOS-specific because:
- **kqueue**: watches inodes, fd becomes stale when inode deleted
- **inotify (Linux)**: watches paths, gets `IN.MOVED_TO` (not
`IN.MOVE_SELF`), so files stay in watchlist

## Solution

When the entrypoint receives `NOTE_RENAME` on macOS:
1. Set `is_waiting_for_dir_change` flag
2. Skip immediate reload
3. Wait for parent directory `NOTE_WRITE` event
4. Use `faccessat()` to verify file exists
5. Trigger reload

This only applies to the entrypoint because dependencies have buffering
time during import graph traversal.

## Test Plan

Manual testing with vim on macOS:
1. Run `bun --hot entrypoint.js`
2. Edit entrypoint with vim (`:w`)
3. Verify no "Module not found" errors
4. Verify hot reload succeeds

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

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: taylor.fish <contact@taylor.fish>
2025-10-14 16:33:30 -07:00
robobun
dc36d5601c Improve FFI error messages when symbol is missing ptr field (#23585)
### What does this PR do?

Fixes unhelpful FFI error messages that made debugging extremely
difficult. The user reported that when dlopen fails, the error doesn't
tell you which library failed or why.

**Before:**
```
Failed to open library. This is usually caused by a missing library or an invalid library path.
```

**After:**
```
Failed to open library "libnonexistent.so": /path/libnonexistent.so: cannot open shared object file: No such file or directory
```

### How did you verify your code works?

1. **Cross-platform compilation verified**
- Ran `bun run zig:check-all` - all platforms compile successfully
(Windows, macOS x86_64/arm64, Linux x86_64/arm64 glibc/musl)

2. **Added comprehensive regression tests**
(`test/regression/issue/dlopen-missing-symbol-error.test.ts`)
   -  Tests dlopen error shows library name when it can't be opened
   -  Tests dlopen error shows symbol name when symbol isn't found
   -  Tests linkSymbols shows helpful error when ptr is missing
   -  Tests handle both glibc and musl libc systems

3. **Manually tested error messages**
   - Missing library: Shows full path and "No such file or directory"
   - Invalid library: Shows "invalid ELF header"
   - Missing symbol: Shows symbol and library name
   - linkSymbols without ptr: Shows helpful explanation

### Implementation Details

1. **Created cross-platform getDlError() helper**
(src/bun.js/api/ffi.zig:8-21)
- On POSIX: Calls `std.c.dlerror()` to get actual system error message
- On Windows: Returns generic message (detailed errors handled in C++
layer via `GetLastError()` + `FormatMessageW()`)
- Follows the pattern established in `BunProcess.cpp` for dlopen error
handling

2. **Improved error messages**
   - dlopen errors now include library name and system error details
   - linkSymbols errors explain the ptr field requirement clearly
   - Symbol lookup errors already showed both symbol and library name

3. **Fixed linkSymbols error propagation** (src/js/bun/ffi.ts:529)
   - Added missing `if (Error.isError(result)) throw result;` check
   - Now consistent with dlopen which already had this check

### Example Error Messages

- **Missing library:** `Failed to open library "libnonexistent.so":
cannot open shared object file: No such file or directory`
- **Invalid library:** `Failed to open library "/etc/passwd": invalid
ELF header`
- **Missing symbol:** `Symbol "nonexistent_func" not found in
"libc.so.6"`
- **Missing ptr:** `Symbol "myFunc" is missing a "ptr" field. When using
linkSymbols() or CFunction()...`

Fixes the issue mentioned in:
https://fxtwitter.com/hassanalinali/status/1977710104334963015

🤖 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>
2025-10-14 14:38:17 -07:00
robobun
9086b8f203 Remove copyright header from FormatStackTraceForJS.cpp (#23665) 2025-10-14 10:38:21 -07:00
robobun
6d1ea1c14e Refactor: Move error stack trace code to FormatStackTraceForJS (#23558) 2025-10-14 10:17:47 -07:00
Jarred Sumner
bd88717ddc codegen: Add WriteBarrierEarlyInit support for classes with values and valuesArray (#23624)
## Summary

Adds comprehensive support to `generate-classes.ts` for JavaScript
classes that need both named WriteBarrier members (like callbacks) and a
dynamic array of JSValues, all properly tracked by the garbage
collector. This replaces error-prone manual `protect()/unprotect()`
calls with proper GC integration.

## Motivation

The shell interpreter was using `JSValue.protect()/unprotect()` to keep
JavaScript objects alive, which caused memory leaks when cleanup paths
didn't properly unprotect values. This is a common pattern that needed a
better solution.

## What Changed

### Code Generator (`generate-classes.ts`)

When a class has both `values: ["resolve", "reject"]` and `valuesArray:
true`:

**Generated C++ class gets:**
- `WTF::FixedVector<JSC::WriteBarrier<JSC::Unknown>> jsvalueArray`
member for dynamic array
- Individual `JSC::WriteBarrier<JSC::Unknown> m_resolve, m_reject`
members for named values
- 4 `create()` overloads covering all combinations:
  1. Basic: `create(vm, globalObject, structure, ptr)`
  2. Array only: `create(..., FixedVector<WriteBarrier<Unknown>>&&)`
  3. Named values: `create(..., JSValue resolve, JSValue reject)` 
  4. Both: `create(..., FixedVector&&, JSValue resolve, JSValue reject)`

**Constructor overloads using `WriteBarrierEarlyInit`:**
```cpp
JSShellInterpreter(VM& vm, Structure* structure, void* ptr, 
                   JSValue resolve, JSValue reject)
    : Base(vm, structure)
    , m_resolve(resolve, JSC::WriteBarrierEarlyInit)  // ← Key technique
    , m_reject(reject, JSC::WriteBarrierEarlyInit)
{
    m_ctx = ptr;
}
```

The `WriteBarrierEarlyInit` tag allows initializing WriteBarriers in the
constructor initializer list before the object is fully constructed,
which is required for proper GC integration.

**Extern C bridge functions:**
- `TypeName__createWithValues(globalObject, ptr, markedArgumentBuffer*)`
- `TypeName__createWithInitialValues(globalObject, ptr, resolve,
reject)`
- `TypeName__createWithValuesAndInitialValues(globalObject, ptr,
buffer*, resolve, reject)`

**Zig convenience wrappers:**
- `toJSWithValues(this, globalObject, markedArgumentBuffer)`
- `toJSWithInitialValues(this, globalObject, resolve, reject)`
- `toJSWithValuesAndInitialValues(this, globalObject, buffer, resolve,
reject)`

### Shell Interpreter Memory Leak Fix

**Before:**
```zig
const js_value = JSShellInterpreter.toJS(interpreter, globalThis);
resolve.protect();  // Manual reference counting
reject.protect();
// ... later in cleanup ...
resolve.unprotect();  // Easy to forget/miss in error paths
reject.unprotect();
```

**After:**
```zig
const js_value = Bun__createShellInterpreter(
    globalThis, 
    interpreter,
    parsed_shell_script,
    resolve,  // Stored with WriteBarrierEarlyInit
    reject,   // GC tracks automatically
);
// No manual memory management needed!
```

### Supporting Changes

- Added `MarkedArgumentBuffer.wrap()` helper in Zig for safe
MarkedArgumentBuffer usage
- Created `ShellBindings.cpp` with `Bun__createShellInterpreter()` using
the new API
- Removed all `protect()/unprotect()` calls from shell interpreter
- Applied pattern to both `ShellInterpreter` and `ShellArgs` classes

## Benefits

1. **No memory leaks**: GC tracks all references automatically
2. **Safer**: Cannot forget to unprotect values
3. **Cleaner code**: No manual reference counting
4. **Reusable**: Pattern works for any class needing to store JSValues
5. **Performance**: Same cost as manual protect/unprotect but safer

## Testing

Existing shell tests verify the functionality. The pattern is already
used throughout JavaScriptCore for similar cases (see
`JSWrappingFunction`, `AsyncContextFrame`, `JSModuleMock`, etc.)

## When to Use This Pattern

Use `values` + `valuesArray` + `WriteBarrierEarlyInit` when:
- Your C++ class needs to keep JavaScript values alive
- You have both known named callbacks AND dynamic arrays of values
- You want the GC to track references instead of manual
protect/unprotect
- Your class extends `JSDestructibleObject`

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

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

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-13 19:15:38 -07:00
Jarred Sumner
9c37549e0c Update ParsedShellScript.zig 2025-10-13 14:59:53 -07:00
Dylan Conway
72900ec688 fix(install): EXDEV handling with linker: "isolated" (#23587)
### What does this PR do?
Handles EXDEV correctly after first clonefile fails with ENOENT

Fixes #23579
Fixes #23577
### How did you verify your code works?
Manually

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-13 11:19:17 -07:00
Dylan Conway
c820c2b0d3 fix(parser): advance by enum scopes length during visiting (#23581)
### What does this PR do?
Matches esbuild behavior.

Fixes #23578
### How did you verify your code works?
Added a test.
2025-10-13 05:11:54 -07:00
robobun
db7bcd79ff Refactor: move ZigException functions to dedicated file (#23560)
## Summary

This PR moves error-related functions from `bindings.cpp` into a new
dedicated file `ZigException.cpp` for better code organization.

## Changes

Moved the following functions to `ZigException.cpp`:
- `populateStackFrameMetadata`
- `populateStackFramePosition`  
- `populateStackFrame`
- `populateStackTrace`
- `fromErrorInstance`
- `exceptionFromString`
- `JSC__JSValue__toZigException`
- `ZigException__collectSourceLines`
- `JSC__Exception__getStackTrace`

Also moved helper functions and types:
- `V8StackTraceIterator` class
- `getNonObservable`
- `PopulateStackTraceFlags` enum
- `StringView_slice` helper
- `SYNTAX_ERROR_CODE` macro

## Test plan

- Built successfully with `bun bd`
- All exception handling functions are properly exported
- No functional changes, pure refactoring

🤖 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>
2025-10-12 16:29:56 -07:00
robobun
caa4f54b2e refactor: move ReadableStream-related functions from ZigGlobalObject.cpp to ReadableStream.cpp (#23547)
## Summary

This PR moves all ReadableStream-related functions from
`ZigGlobalObject.cpp` to `ReadableStream.cpp` for better code
organization and maintainability.

## Changes

Moved 17 functions from `ZigGlobalObject.cpp` to `ReadableStream.cpp`:

### Core ReadableStream Functions
- `ReadableStream__tee` - with `invokeReadableStreamFunction` helper
(converted to lambda)
- `ReadableStream__cancel`
- `ReadableStream__detach`
- `ReadableStream__isDisturbed`
- `ReadableStream__isLocked`
- `ReadableStreamTag__tagged`

### Stream Creation & Conversion
- `ZigGlobalObject__createNativeReadableStream`
- `ZigGlobalObject__readableStreamToArrayBufferBody`
- `ZigGlobalObject__readableStreamToArrayBuffer`
- `ZigGlobalObject__readableStreamToBytes`
- `ZigGlobalObject__readableStreamToText`
- `ZigGlobalObject__readableStreamToFormData`
- `ZigGlobalObject__readableStreamToJSON`
- `ZigGlobalObject__readableStreamToBlob`

### Host Functions
- `functionReadableStreamToArrayBuffer`
- `functionReadableStreamToBytes`

## Technical Details

### File Changes
- **ReadableStream.cpp**: Added necessary includes and all
ReadableStream functions
- **ReadableStream.h**: Added forward declarations for code generator
functions
- **ZigGlobalObject.cpp**: Removed moved functions (394 lines removed)

### Implementation Notes
- Added proper namespace declarations (`using namespace JSC; using
namespace WebCore;`) to all extern "C" functions
- Used correct namespace qualifiers for types (e.g., `Bun::IDLRawAny`,
`Bun::AbortError`)
- Added required includes: `WebCoreJSBuiltins.h`, `ZigGlobalObject.h`,
`ZigGeneratedClasses.h`, `helpers.h`, `BunClientData.h`,
`BunIDLConvert.h`

## Testing

-  Builds successfully with debug configuration
-  All functions maintain identical behavior
-  No API changes

## Benefits

1. **Better code organization**: ReadableStream functionality is now
consolidated in one place
2. **Improved maintainability**: Easier to find and modify
ReadableStream-related code
3. **Reduced file size**: `ZigGlobalObject.cpp` is now ~400 lines
smaller

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
2025-10-12 14:54:58 -07:00
robobun
f00e1816ef Fix crash handler not dumping stack traces on Linux aarch64 (#23549)
### What does this PR do?

Fixes the crash handler failing to capture and display stack traces on
Linux ARM64 systems.

**Before:**
```
============================================================
panic(main thread): cast causes pointer to be null
```
No stack trace shown.

**After:**
```
============================================================
panic(main thread): cast causes pointer to be null
bun.js.api.FFIObject.Reader.u8
/workspace/bun/src/bun.js/api/FFIObject.zig:67:41

bun.js.jsc.host_fn.toJSHostCall__anon_2545765
/workspace/bun/src/bun.js/jsc/host_fn.zig:93:5
```
Full stack trace with source locations.

#### Root Cause
- Zig's `std.debug.captureStackTrace` uses `StackIterator.init()` which
falls back to frame pointer-based unwinding when no context is provided
- Frame pointer-based unwinding doesn't work reliably on ARM64, even
with `-fno-omit-frame-pointer` enabled
- This resulted in 0 frames being captured (`trace.index == 0`)

#### Changes
1. **Use glibc's backtrace() on Linux**: On Linux with glibc (not musl),
always use glibc's `backtrace()` function instead of Zig's
StackIterator. glibc's implementation properly uses DWARF unwinding
information from `.eh_frame` sections.

2. **Skip crash handler frames**: After capturing with `backtrace()`,
find the desired `begin_addr` in the trace (within 128 byte tolerance)
and filter out crash handler internal frames for cleaner output. If
`begin_addr` is not found, use the complete backtrace.

3. **Preserve existing behavior**:
   - Non-debug builds: Use WTF printer (fast, no external deps)
- Debug builds: Fall through to llvm-symbolizer (detailed source info)

### How did you verify your code works?

Reproduced the crash:
```bash
bun-debug --print 'Bun.FFI.read.u8(0)'
```

Verified that:
-  Stack traces now appear on Linux ARM64 with proper source locations
-  Crash handler frames are properly filtered out
-  llvm-symbolizer integration works for debug builds
-  WTF printer is used for release builds
-  When begin_addr is not found, complete backtrace is used

🤖 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>
2025-10-12 14:00:11 -07:00
robobun
356d0e491c fix: use std::call_once for thread-safe JSC initialization (#23542)
## What does this PR do?

Fixes a race condition where multiple threads could attempt to
initialize JavaScriptCore concurrently when the bundler's thread pool
processes files with macros.

Fixes #23540

## How did you verify your code works?

Reproduced the segfault with the Brisa project build and verified the
fix resolves it:

```bash
git clone https://github.com/brisa-build/brisa
cd brisa
bun install
bun run build
```

Before the fix: Segmentation fault with assertion failure
After the fix: Build proceeds without crashing

## Root Cause

The previous implementation used a simple boolean flag `has_loaded_jsc`
without synchronization. When multiple bundler threads tried to execute
macros simultaneously, they could race through the initialization check
before `JSC::initialize()` finished finalizing options on another
thread.

This caused crashes with:
```
ASSERTION FAILED: g_jscConfig.options.allowUnfinalizedAccess || g_jscConfig.options.isFinalized
vendor/WebKit/Source/JavaScriptCore/runtime/Options.h(146) : static OptionsStorage::Bool &JSC::Options::forceTrapAwareStackChecks()
```

## The Fix

Replace the boolean flag with `std::call_once`, which provides:
- Thread-safe initialization
- Guaranteed exactly-once execution
- Proper memory barriers to ensure visibility across threads

The initialization code is now wrapped in a lambda passed to
`std::call_once`, capturing the necessary parameters (`evalMode`,
`envp`, `envc`, `onCrash`).

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

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

---------

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>
2025-10-12 13:55:01 -07:00
robobun
755b41e85b Add BUN_WATCHER_TRACE environment variable for debugging file watcher events (#23533)
## Summary

Adds `BUN_WATCHER_TRACE` environment variable that logs all file watcher
events to a JSON file for debugging. When set, the watcher appends
detailed event information to the specified file path.

## Motivation

Debugging watch-related issues (especially with `bun --watch` and `bun
--hot`) can be difficult without visibility into what the watcher is
actually seeing. This feature provides detailed trace logs showing
exactly which files are being watched and what events are triggered.

## Implementation

- **Isolated module** (`src/watcher/WatcherTrace.zig`) - All trace logic
in separate file
- **No locking needed** - Watcher runs on its own thread, no mutex
required
- **Append-only mode** - Traces persist across multiple runs for easier
debugging
- **Silent errors** - Won't break functionality if trace file can't be
created
- **JSON format** - Easy to parse and analyze

## Usage

```bash
BUN_WATCHER_TRACE=/tmp/watch.log bun --watch script.js
BUN_WATCHER_TRACE=/tmp/hot.log bun --hot server.ts
```

## JSON Output Format

Each line is a JSON object with:
```json
{
  "timestamp": 1760280923269,
  "index": 0,
  "path": "/path/to/watched/file.js",
  "delete": false,
  "write": true,
  "rename": false,
  "metadata": false,
  "move_to": false,
  "changed_files": ["script.js"]
}
```

## Testing

All tests use stdout streaming to wait for actual reloads (no
sleeps/timeouts):
- Tests with `--watch` flag
- Tests with `fs.watch` API  
- Tests that trace file appends across multiple runs
- Tests validation of JSON format and event details

```
 4 pass
 0 fail
📊 52 expect() calls
```

## Files Changed

- `src/Watcher.zig` - Minimal integration with WatcherTrace module
- `src/watcher/WatcherTrace.zig` - New isolated trace implementation
- `src/watcher/KEventWatcher.zig` - Calls writeTraceEvents before
onFileUpdate
- `src/watcher/INotifyWatcher.zig` - Calls writeTraceEvents before
onFileUpdate
- `src/watcher/WindowsWatcher.zig` - Calls writeTraceEvents before
onFileUpdate
- `test/cli/watch/watcher-trace.test.ts` - Comprehensive tests

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

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

---------

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>
2025-10-12 11:29:48 -07:00
robobun
40da082349 fix(shell): handle UV_ENOTCONN gracefully in shell subprocess (#23520) 2025-10-12 05:40:02 -07:00
robobun
5bdc32265d Add support for localAddress and localPort in TCP connections (#23464)
## Summary

This PR implements support for `localAddress` and `localPort` options in
TCP connections, allowing users to bind outgoing connections to a
specific local IP address and port.

This addresses issue #6888 and implements Node.js-compatible behavior
for these options.

## Changes

### C Layer (uSockets)
- **`bsd.c`**: Modified `bsd_create_connect_socket()` to accept a
`local_addr` parameter and call `bind()` before `connect()` when a local
address is specified
- **`context.c`**: Updated `us_socket_context_connect()` and
`start_connections()` to parse and pass local address parameters through
the connection flow
- **`libusockets.h`**: Updated public API signatures to include
`local_host` and `local_port` parameters
- **`internal.h`**: Added `local_host` and `local_port` fields to
`us_connecting_socket_t` structure
- **`openssl.c`**: Updated SSL connection function to match the new
signature

### Zig Layer
- **`SocketContext.zig`**: Updated `connect()` method to accept and pass
through `local_host` and `local_port` parameters
- **`socket.zig`**: Modified `connectAnon()` to handle local address
binding, including IPv6 bracket removal and proper memory management
- **`Handlers.zig`**: Added `localAddress` and `localPort` fields to
`SocketConfig` and implemented parsing from JavaScript options
- **`Listener.zig`**: Updated connection structures to store and pass
local binding information
- **`socket.zig` (bun.js/api/bun)**: Modified `doConnect()` to extract
and pass local address options
- Updated all other call sites (HTTP, MySQL, PostgreSQL, Valkey) to pass
`null, 0` for backward compatibility

### JavaScript Layer
- **`net.ts`**: Enabled `localAddress` and `localPort` support by
passing these options to `doConnect()` and removing TODO comments

### Tests
- **`06888-localaddress.test.ts`**: Added comprehensive tests covering:
  - IPv4 local address binding
  - IPv4 local address and port binding
  - IPv6 local address binding (loopback)
  - Backward compatibility (connections without local address)

## Test Results

All tests pass successfully:
```
✓ TCP socket can bind to localAddress - IPv4
✓ TCP socket can bind to localAddress and localPort - IPv4
✓ TCP socket can bind to localAddress - IPv6 loopback
✓ TCP socket without localAddress works normally

4 pass, 0 fail
```

## API Usage

```typescript
import net from "net";

// Connect with a specific local address
const client = net.createConnection({
  host: "example.com",
  port: 80,
  localAddress: "192.168.1.100",  // Bind to this local IP
  localPort: 0,                    // Let system assign port (optional)
});
```

## Implementation Details

The implementation follows the same flow as Node.js:
1. JavaScript options are parsed in `Handlers.zig` 
2. Local address/port are stored in the connection configuration
3. The Zig layer processes and passes them to the C layer
4. The C layer parses the local address and calls `bind()` before
`connect()`
5. Both IPv4 and IPv6 addresses are supported

Memory management is handled properly throughout the stack, with
appropriate allocation/deallocation at each layer.

Closes #6888

🤖 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>
2025-10-11 20:54:30 -07:00
Dylan Conway
01924e9993 fix(YAML.stringify): check for more indicators at the beginning of strings (#23516)
### What does this PR do?
Makes sure strings are doubled quoted when they start with flow
indicators and `:`.

Fixes #23502
### How did you verify your code works?
Added tests for each indicator in flow and block context
2025-10-11 20:51:22 -07:00
Jarred Sumner
d963a05907 Reduce # of redundant resolver syscalls #2 (#23506)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-11 19:53:05 -07:00
Jarred Sumner
8ccd17fe87 Make sourcemap generation faster (#23514)
### What does this PR do?

### How did you verify your code works?
2025-10-11 19:51:58 -07:00
Jarred Sumner
0e29617d4b Add missing error handling for directory entries errors (#23511)
### What does this PR do?

Add missing error handling for directory entries errors

The code was missing a check for .err

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-11 19:21:14 -07:00
Jarred Sumner
c766c14928 Reduce # of redundant system calls in module resolver (#23505)
### What does this PR do?

### How did you verify your code works?
2025-10-11 14:57:15 -07:00
robobun
525315cf39 fix: include cookies in WebSocket upgrade response (#23499)
Fixes #23474

## Summary

When `request.cookies.set()` is called before `server.upgrade()`, the
cookies are now properly included in the WebSocket upgrade response
headers.

## Problem

Previously, cookies set on the request via `req.cookies.set()` were only
written for regular HTTP responses but were ignored during WebSocket
upgrades. Users had to manually pass cookies via the `headers` option:

```js
server.upgrade(req, {
  headers: {
    "Set-Cookie": `SessionId=${sessionId}`,
  },
});
```

## Solution

Modified `src/bun.js/api/server.zig` to check for and write cookies to
the WebSocket upgrade response after the "101 Switching Protocols"
status is set but before the actual upgrade is performed.

The fix handles both cases:
- When `upgrade()` is called without custom headers
- When `upgrade()` is called with custom headers

## Testing

Added comprehensive regression tests in
`test/regression/issue/23474.test.ts` that:
- Verify cookies are set in the upgrade response without custom headers
- Verify cookies are set in the upgrade response with custom headers
- Use `Promise.withResolvers()` for efficient async handling (no
arbitrary timeouts)

Tests confirmed:
-  Fail with system bun v1.2.23 (without fix)
-  Pass with debug build v1.3.0 (with fix)

## Manual verification

```bash
curl -i -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  -H "Sec-WebSocket-Version: 13" \
  http://localhost:3000/ws
```

Response now includes:
```
HTTP/1.1 101 Switching Protocols
Set-Cookie: test=123; Path=/; SameSite=Lax
Upgrade: websocket
Connection: Upgrade
...
```

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-11 13:34:06 -07:00
Dylan Conway
85a2ebb717 fix #23470 (#23471)
### What does this PR do?
`CompileResult` error message memory was not managed correctly.

Fixes #23470

### How did you verify your code works?
Manually
2025-10-11 08:23:25 -07:00
Paweł Zatoka
f673ed8821 fix: fix broken scripts in the React templates after the index.ts rename (#23472) 2025-10-10 22:49:45 -07:00
Paweł Zatoka
a67ac081f1 fix: rename index.tsx in React project templates to index.ts (#23469) 2025-10-10 18:35:54 -07:00
robobun
8197a5f7af Fix WriteBarrier initialization to use WriteBarrierEarlyInit (#23435)
## Summary

This PR fixes incorrect WriteBarrier initialization patterns throughout
the Bun codebase where `.set()` or `.setEarlyValue()` was being called
in the constructor body or in `finishCreation()`. According to
JavaScriptCore's `WriteBarrier.h`, WriteBarriers that are initialized
during construction should use the `WriteBarrierEarlyInit` constructor
in the initializer list to avoid triggering unnecessary write barriers.

## Changes

The following classes were updated to properly initialize WriteBarrier
fields:

1. **InternalModuleRegistry** - Initialize internal fields in
constructor using `setWithoutWriteBarrier()` instead of calling `.set()`
in `finishCreation()`
2. **AsyncContextFrame** - Pass callback and context to constructor and
use `WriteBarrierEarlyInit`
3. **JSCommonJSModule** - Pass id, filename, dirname to constructor and
use `WriteBarrierEarlyInit`
4. **JSMockImplementation** - Pass initial values to constructor and use
`WriteBarrierEarlyInit`
5. **JSConnectionsList** - Pass connection sets to constructor and use
`WriteBarrierEarlyInit`
6. **JSBunRequest** - Pass params to constructor and initialize both
`m_params` and `m_cookies` using `WriteBarrierEarlyInit`
7. **JSNodeHTTPServerSocket** - Initialize `currentResponseObject` using
`WriteBarrierEarlyInit` instead of calling `setEarlyValue()`

## Why This Matters

From JavaScriptCore's `WriteBarrier.h`:

```cpp
enum WriteBarrierEarlyInitTag { WriteBarrierEarlyInit };

// Constructor for early initialization during object construction
WriteBarrier(T* value, WriteBarrierEarlyInitTag)
{
    this->setWithoutWriteBarrier(value);
}
```

Using `WriteBarrierEarlyInit` during construction:
- Avoids triggering write barriers when they're not needed
- Is the correct pattern for initializing WriteBarriers before the
object is fully constructed
- Aligns with JavaScriptCore best practices

## Testing

-  Full debug build completes successfully
-  Basic functionality tested (CommonJS modules, HTTP requests, Node
HTTP servers)
-  No regressions observed

## Note on generate-classes.ts

The code generator (`generate-classes.ts`) does not need updates because
generated classes intentionally leave WriteBarrier fields (callbacks,
cached fields, values) uninitialized. They start with
default-constructed WriteBarriers and are populated later by Zig code
via setter functions, which is the correct pattern for those fields.

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
2025-10-10 03:53:04 -07:00
pfg
c50db1dbfb fix unpaired deref when write_file fails due to nametoolong (#23438)
Fixes test\regression\issue\23316-long-path-spawn.test.ts

The problem was ``await Bun.write(join(deepPath, "test.js"),
`console.log("hello");`);`` was failing because the name was too long,
but it failed before refConcurrently was called and it called
unrefConcurrently after failing. so then when the subprocess spawned it
didn't ref.

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-10 03:48:47 -07:00
Dylan Conway
312a86fd43 fix writing UTF-16 with a trailing unpaired surrogate to process.stdout/stderr (#23444)
### What does this PR do?
Fixes `bun -p "process.stderr.write('Hello' +
String.fromCharCode(0xd800))"`.

Also fixes potential index out of bounds if there are many invalid
sequences.

This also affects `TextEncoder`.
### How did you verify your code works?
Added tests for edgecases

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-10 03:48:04 -07:00
robobun
8826b4f5f5 Fix WTFTimer issues with Atomics.waitAsync (#23442)
## Summary

Fixes two critical issues in `WTFTimer` when `Atomics.waitAsync` creates
multiple timer instances.

## Problems

### 1. Use-After-Free in `WTFTimer.fire()`

**Location:** `/workspace/bun/src/bun.js/api/Timer/WTFTimer.zig:70-82`

```zig
pub fn fire(this: *WTFTimer, _: *const bun.timespec, _: *VirtualMachine) EventLoopTimer.Arm {
    this.event_loop_timer.state = .FIRED;
    this.imminent.store(null, .seq_cst);
    this.runWithoutRemoving();  // ← Callback might destroy `this`
    return if (this.repeat)     // ← UAF: accessing freed memory
        .{ .rearm = this.event_loop_timer.next }
    else
        .disarm;
}
```

When `Atomics.waitAsync` creates a `DispatchTimer` with a timeout, the
timer fires and the callback destroys `this`, but we continue to access
it.

### 2. Imminent Pointer Corruption

**Location:** `/workspace/bun/src/bun.js/api/Timer/WTFTimer.zig:36-42`

```zig
pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void {
    // Multiple WTFTimers unconditionally overwrite the shared imminent pointer
    this.imminent.store(if (seconds == 0) this else null, .seq_cst);
    // ...
}
```

All `WTFTimer` instances share the same
`vm.eventLoop().imminent_gc_timer` atomic pointer. When multiple timers
are created (GC timer + Atomics.waitAsync timers), they stomp on each
other's imminent state.

## Solutions

### 1. UAF Fix

Read `this.repeat` and `this.event_loop_timer.next` **before** calling
`runWithoutRemoving()`:

```zig
const should_repeat = this.repeat;
const next_time = this.event_loop_timer.next;
this.runWithoutRemoving();
return if (should_repeat)
    .{ .rearm = next_time }
else
    .disarm;
```

### 2. Imminent Pointer Fix

Use compare-and-swap to only set imminent if it's null, and only clear
it if this timer was the one that set it:

```zig
if (seconds == 0) {
    _ = this.imminent.cmpxchgStrong(null, this, .seq_cst, .seq_cst);
    return;
} else {
    _ = this.imminent.cmpxchgStrong(this, null, .seq_cst, .seq_cst);
}
```

## Test Plan

Added regression test at
`test/regression/issue/atomics-waitasync-wtftimer-uaf.test.ts`:

```javascript
const buffer = new SharedArrayBuffer(16);
const view = new Int32Array(buffer);
Atomics.store(view, 0, 0);

const result = Atomics.waitAsync(view, 0, 0, 10);
setTimeout(() => {
  console.log("hi");
}, 100);
```

**Before:** Crashes with UAF under ASAN  
**After:** Runs cleanly

All existing atomics tests 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: Jarred Sumner <jarred@jarredsumner.com>
2025-10-10 03:47:38 -07:00
Jarred Sumner
a686b9fc39 Update package.json 2025-10-09 23:39:37 -07:00
Zack Radisic
a3cf974752 Update bun-plugin-tailwind (#23396)
### What does this PR do?

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-09 23:39:04 -07:00
Ciro Spaciari
3395774c8c improve(node:http): uncork after flushing headers to ensure data is sent immediately (#23413)
### What does this PR do?
Calls `uncork()` after flushing response headers to ensure data is sent
as soon as possible, improving responsiveness.
This behavior still works correctly even without the explicit `uncork()`
call, due to the deferred uncork logic implemented here:

6e3359dd16/packages/bun-uws/src/Loop.h (L57-L64)

A test already covers this scenario in
`test/js/node/test/parallel/test-http-flush-response-headers.js`.


### How did you verify your code works?
CI

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-09 22:56:49 -07:00
Jarred Sumner
b3cfaab07f Fix: after pausing stdin, a subprocess should be able to read from stdin (#23341)
Fixes #23333, Fixes #13978

### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pfg <pfg@pfg.pw>
Co-authored-by: Zack Radisic <zack@theradisic.com>
2025-10-09 19:04:41 -07:00
robobun
6e3359dd16 Bump version to 1.3.0 (#23401)
## What does this PR do?

Bumps Bun version from 1.2.24 to 1.3.0, marking the start of the 1.3.x
release series.

## Changes

- **`package.json`**: Updated version from `1.2.24` to `1.3.0`
- **`LATEST`**: Updated from `1.2.23` to `1.3.0` (used by installation
scripts)
- **`test/bundler/bundler_bun.test.ts`**: Updated version check to
include `1.3.x` so export conditions tests continue to run

## Verification

 Debug build successful showing version `1.3.0-debug`
 All platforms compile successfully via `bun run zig:check-all` (49/49
steps)
 Bundler tests pass with updated version check

## Additional Notes

- CI workflow Bun versions (e.g., `1.2.3`, `1.2.0` in
`.github/workflows/release.yml`) are intentionally left unchanged -
these are pinned versions used to run the release tooling, not the
version being released
- Docker images use `ARG BUN_VERSION` passed at build time and don't
need updates
- The actual release version comes from git tags via `${{
env.BUN_VERSION }}`

---

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

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

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-10-09 06:30:35 -07:00
Dylan Conway
3f0d16d181 fix (node:zlib): use runCallback for calling the error callback (#23397)
### What does this PR do?
Fixes debug panic running `zlib/zlib.test.js`
### How did you verify your code works?
Manually
2025-10-09 04:01:45 -07:00
pfg
46cf50dee5 Fix 23382 (unicode object key printed as 'key" in snapshot instead of "key") (#23390)
Fixes #23382

Breaking change because any existing snapshots that have unicode keys
will need to be regenerated
2025-10-08 21:25:24 -07:00