- Replace union type with TypeScript function overloads for cleaner IntelliSense
- Simplify TOML options to only include `inlineTables` (most essential option)
- Remove `arraysMultiline` and `indent` options for consistent formatting
- Update memory management to use ArenaAllocator for better cleanup
- Update test snapshots to match new array formatting (no multiline for <4 elements)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
## Summary
Fixes an issue where compiled standalone binaries included an extra
executable name argument in `process.argv`, breaking code that uses
`node:util.parseArgs()` with `process.argv.slice(2)`.
## Problem
When running a compiled binary, `process.argv` incorrectly included the
executable name as a third argument:
```bash
./my-app
# process.argv = ["bun", "/$bunfs/root/my-app", "./my-app"] # BUG
```
This caused `parseArgs()` to fail with "Unexpected argument" errors,
breaking previously valid code.
## Solution
Fixed the `offset_for_passthrough` calculation in `cli.zig` to always
skip the executable name for standalone binaries, ensuring
`process.argv` only contains the runtime name and script path:
```bash
./my-app
# process.argv = ["bun", "/$bunfs/root/my-app"] # FIXED
```
## Test plan
- [x] Added regression test in `test/regression/issue/22157.test.ts`
- [x] Verified existing exec-argv functionality still works correctly
- [x] Manual testing confirms the fix resolves the parseArgs issue
Fixes#22157🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Michael H <git@riskymh.dev>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Major features implemented:
- Core TOML stringify functionality with comprehensive error handling
- Support for all basic TOML types: strings, numbers, booleans, arrays, tables
- Options support: inlineTables, arraysMultiline, indent
- Proper string escaping with control character handling
- Special float value support (nan, inf, -inf)
- Key validation and quoting when necessary
- Table and inline table formatting
- TypeScript type definitions with comprehensive documentation
- Comprehensive test suite covering basic and advanced functionality
API Features:
- Bun.TOML.stringify(value, replacer?, options?)
- Options: inlineTables, arraysMultiline, indent
- Error messages for different failure modes
- Round-trip compatibility with Bun.TOML.parse()
The implementation provides a solid foundation for TOML stringification
in Bun, following similar patterns to JSON.stringify and YAML.stringify.
Memory management has been carefully handled to prevent use-after-free
issues in the JavaScript runtime.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
### 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>
### What does this PR do?
Change tinyint/bool type from mysql to number instead of bool to match
mariadb and mysql2 behavior since tinyint/bool can be bigger than 1 in
mysql
Fixes https://github.com/oven-sh/bun/issues/22158
### How did you verify your code works?
Test
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
### How did you verify your code works?
---------
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Updates build instructions in `CONTRIBUTING.md`
### How did you verify your code works?
N/A
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Replace `catch bun.outOfMemory()`, which can accidentally catch
non-OOM-related errors, with either `bun.handleOom` or a manual `catch
|err| switch (err)`.
(For internal tracking: fixes STAB-1070)
---------
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
### What does this PR do?
- Implements .onEnd
Fixes#22061
Once #22144 is merged, this also fixes:
Fixes#9862Fixes#20806
### How did you verify your code works?
Tests
---
TODO in a followup (#22144)
> ~~Make all entrypoints be called in onResolve~~
> ~~Fixes # 9862~~
> ~~Fixes # 20806~~
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
For jest compatibility. Fixes#5228
---------
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>
### What does this PR do?
fixes parsing strings like `"1e18495d9d7f6b41135e5ee828ef538dc94f9be4"`
### How did you verify your code works?
added a test.
## Summary
Fixes an issue where `--compile-exec-argv` options were incorrectly
appearing in `process.argv` when no user arguments were provided to a
compiled standalone binary.
## Problem
When building a standalone binary with `--compile-exec-argv`, the exec
argv options would leak into `process.argv` when running the binary
without any user arguments:
```bash
# Build with exec argv
bun build --compile-exec-argv="--user-agent=hello" --compile ./a.js
# Run without arguments - BEFORE fix
./a
# Output showed --user-agent=hello in both execArgv AND argv (incorrect)
{
execArgv: [ "--user-agent=hello" ],
argv: [ "bun", "/$bunfs/root/a", "--user-agent=hello" ], # <- BUG: exec argv leaked here
}
# Expected behavior (matches runtime):
bun --user-agent=hello a.js
{
execArgv: [ "--user-agent=hello" ],
argv: [ "/path/to/bun", "/path/to/a.js" ], # <- No exec argv in process.argv
}
```
## Solution
The issue was in the offset calculation for determining which arguments
to pass through to the JavaScript runtime. The offset was being
calculated before modifying the argv array with exec argv options,
causing it to be incorrect when the original argv only contained the
executable name.
The fix ensures that:
- `process.execArgv` correctly contains the compile-exec-argv options
- `process.argv` only contains the executable, script path, and user
arguments
- exec argv options never leak into `process.argv`
## Test plan
Added comprehensive tests to verify:
1. Exec argv options don't leak into process.argv when no user arguments
are provided
2. User arguments are properly passed through when exec argv is present
3. Existing behavior continues to work correctly
All tests pass:
```
bun test compile-argv.test.ts
✓ 3 tests pass
```
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This PR adds `Bun.secrets`, a new API for securely storing and
retrieving credentials using the operating system's native credential
storage locally. This helps developers avoid storing sensitive data in
plaintext config files.
```javascript
// Store a GitHub token securely
await Bun.secrets.set({
service: "my-cli-tool",
name: "github-token",
value: "ghp_xxxxxxxxxxxxxxxxxxxx"
});
// Retrieve it when needed
const token = await Bun.secrets.get({
service: "my-cli-tool",
name: "github-token"
});
// Use with fallback to environment variable
const apiKey = await Bun.secrets.get({
service: "my-app",
name: "api-key"
}) || process.env.API_KEY;
```
Marking this as a draft because Linux and Windows have not been manually
tested yet. This API is only really meant for local development usecases
right now, but it would be nice if in the future to support adapters for
production or CI usecases.
### Core API
- `Bun.secrets.get({ service, name })` - Retrieve a stored credential
- `Bun.secrets.set({ service, name, value })` - Store or update a
credential
- `Bun.secrets.delete({ service, name })` - Delete a stored credential
### Platform Support
- **macOS**: Uses Keychain Services via Security.framework
- **Linux**: Uses libsecret (works with GNOME Keyring, KWallet, etc.)
- **Windows**: Uses Windows Credential Manager via advapi32.dll
### Implementation Highlights
- Non-blocking - all operations run on the threadpool
- Dynamic loading - no hard dependencies on system libraries
- Sensitive data is zeroed after use
- Consistent API across all platforms
## Use Cases
This API is particularly useful for:
- CLI tools that need to store authentication tokens
- Development tools that manage API keys
- Any tool that currently stores credentials in `~/.npmrc`,
`~/.aws/credentials` or in environment variables that're globally loaded
## Testing
Comprehensive test suite included with coverage for:
- Basic CRUD operations
- Empty strings and special characters
- Unicode support
- Concurrent operations
- Error handling
All tests pass on macOS. Linux and Windows implementations are complete
but would benefit from additional platform testing.
## Documentation
- Complete API documentation in `docs/api/secrets.md`
- TypeScript definitions with detailed JSDoc comments and examples
---------
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>
### What does this PR do?
This PR adds builtin YAML parsing with `Bun.YAML.parse`
```js
import { YAML } from "bun";
const items = YAML.parse("- item1");
console.log(items); // [ "item1" ]
```
Also YAML imports work just like JSON and TOML imports
```js
import pkg from "./package.yaml"
console.log({ pkg }); // { pkg: { name: "pkg", version: "1.1.1" } }
```
### How did you verify your code works?
Added some tests for YAML imports and parsed values.
---------
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>
* `IncrementalGraph(.client).File` packs its fields in a specific way to
save space, but it makes the struct hard to use and error-prone (e.g.,
untagged unions with tags stored in a separate `flags` struct). This PR
changes `File` to have a human-readable layout, but adds methods to
convert it to and from `File.Packed`, a packed version with the same
space efficiency as before.
* Reduce the need to pass the dev allocator to functions (e.g.,
`deinit`) by storing it as a struct field via the new `DevAllocator`
type. This type has no overhead in release builds, or when
`AllocationScope` is disabled.
* Use owned pointers in `PackedMap`.
* Use `bun.ptr.Shared` for `PackedMap` instead of the old
`bun.ptr.RefPtr`.
* Add `bun.ptr.ScopedOwned`, which is like `bun.ptr.Owned`, but can
store an `AllocationScope`. No overhead in release builds or when
`AllocationScope` is disabled.
* Reduce redundant allocators in `BundleV2`.
* Add owned pointer conversions to `MutableString`.
* Make `AllocationScope` behave like a pointer, so it can be moved
without invalidating allocations. This eliminates the need for
self-references.
* Change memory cost algorithm so it doesn't rely on “dedupe bits”.
These bits used to take advantage of padding but there is now no padding
in `PackedMap`.
* Replace `VoidFieldTypes` with `useAllFields`; this eliminates the need
for `voidFieldTypesDiscardHelper`.
(For internal tracking: fixes STAB-1035, STAB-1036, STAB-1037,
STAB-1038, STAB-1039, STAB-1040, STAB-1041, STAB-1042, STAB-1043,
STAB-1044, STAB-1045)
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixes an assertion failure that occurred when `server.stop()` was called
while HTTP requests were still in flight.
## Root Cause
The issue was in `jsValueAssertAlive()` at
`src/bun.js/api/server.zig:627`, which had an assertion requiring
`server.listener != null`. However, `server.stop()` immediately sets
`listener` to null, causing assertion failures when pending requests
triggered callbacks that accessed the server's JavaScript value.
## Solution
Converted the server's `js_value` from `jsc.Strong.Optional` to
`jsc.JSRef` for safer lifecycle management:
- **On `stop()`**: Downgrade from strong to weak reference instead of
calling `deinit()`
- **In `finalize()`**: Properly call `deinit()` on the JSRef
- **Remove problematic assertion**: JSRef allows safe access to JS value
via weak reference even after stop
## Benefits
- ✅ No more assertion failures when stopping servers with pending
requests
- ✅ In-flight requests can still access the server JS object safely
- ✅ JS object can be garbage collected when appropriate
- ✅ Maintains backward compatibility - no external API changes
## Test plan
- [x] Reproduces the original assertion failure
- [x] Verifies the fix resolves the issue
- [x] Adds regression test to prevent future occurrences
- [x] Confirms normal server functionality still works
The fix includes a comprehensive regression test at
`test/regression/issue/server-stop-with-pending-requests.test.ts`.
🤖 Generated with [Claude Code](https://claude.ai/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>
## Summary
- Implement `Symbol.asyncDispose` for the `Worker` class in
`worker_threads` module
- Enables automatic resource cleanup with `await using` syntax
- Calls `await this.terminate()` to properly shut down workers when they
go out of scope
## Implementation Details
The implementation adds a simple async method to the Worker class:
```typescript
async [Symbol.asyncDispose]() {
await this.terminate();
}
```
This allows workers to be used with the new `await using` syntax for
automatic cleanup:
```javascript
{
await using worker = new Worker('./worker.js');
// worker automatically terminates when leaving this scope
}
```
## Test Plan
- [x] Added comprehensive tests for `Symbol.asyncDispose` functionality
- [x] Tests verify the method exists and returns undefined
- [x] Tests verify `await using` syntax works correctly for automatic
worker cleanup
- [x] All new tests pass
- [x] Existing worker_threads functionality remains intact
🤖 Generated with [Claude Code](https://claude.ai/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>
### What does this PR do?
Support the following:
```javascript
const nom = await sql`SELECT name FROM food WHERE category IN ${sql(['bun', 'baozi', 'xiaolongbao'])}`;
```
Previously, only e.g., `sql([1, 2, 3])` was supported.
To be honest I'm not sure what the semantics of SQLHelper *ought* to be.
I'm pretty sure objects ought to be auto-inferred. I'm not sure about
arrays, but given the rest of the code in `SQLHelper` trying to read the
tea leaves on stringified numeric keys I figured someone cared about
this use case. I don't know about other types, but I'm pretty sure that
`Object.keys("bun") === [0, 1, 2]` is an oversight and unintended.
(Incidentally, the reason numbers previously worked is because
`Object.keys(4) === []`). I decided that all non-objects and non-arrays
should be treated as not having auto-inferred columns.
Fixes#18637
### How did you verify your code works?
I wrote a test, but was unable to run it (or any other tests in this
file) locally due to Docker struggles. I sure hope it works!
### What does this PR do?
This PR fixes https://github.com/oven-sh/bun/issues/19131.
I am not 100% certain that this fix is correct as I am still nebulous
regarding some decisions I've made in this PR. I'll try to provide my
reasoning and would love to be proven wrong:
#### Re-authentication
- The `is_authenticated` flag needs to be reset to false. When the
lifecycle reaches a point of attempting to connect, it sends out a
`HELLO 3`, and receives a response. `handleResponse()` is fired and does
not correctly handle it because there is a guard at the top of the
function:
```zig
if (!this.flags.is_authenticated) {
this.handleHelloResponse(value);
// We've handled the HELLO response without consuming anything from the command queue
return;
}
```
Rather, it treats this packet as a regular data packet and complains
that it doesn't have a promise to associate it to. By resetting the
`is_authenticated` flag to false, we guarantee that we handle the `HELLO
3` packet as an authentication packet.
It also seems to make semantic sense since dropping a connection implies
you dropped authentication.
#### Retry Attempts
I've deleted the `retry_attempts = 0` in `reconnect()` because I noticed
that we would never actually re-attempt to reconnect after the first
attempt. Specifically, I was expecting `valkey.zig:459` to potentially
fire multiple times, but it only ever fired once. Removing this reset to
zero caused successful reattempts (in my case 3 of them).
```zig
debug("reconnect in {d}ms (attempt {d}/{d})", .{ delay_ms, this.retry_attempts, this.max_retries });
```
I'm still iffy on whether this is necessary, but I think it makes sense.
```zig
this.client.retry_attempts = 0
```
### How did you verify your code works?
I have added a small unit test. I have compared mainline `bun`, which
fails that test, to this fix, which passes the test.
---------
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
### What does this PR do?
Fixes#20729
### How did you verify your code works?
There is a test
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Add MySQL support, Refactor will be in a followup PR
### How did you verify your code works?
A lot of tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: cirospaciari <6379399+cirospaciari@users.noreply.github.com>
### What does this PR do?
Fixes#22014
todo:
- [x] not spawn sync
- [x] better comm to subprocess (not stderr)
- [x] tty
- [x] more tests (also include some tests for the actual implementation
of a provider)
- [x] disable autoinstall?
Scanner template: https://github.com/oven-sh/security-scanner-template
<!-- **Please explain what your changes do**, example: -->
<!--
This adds a new flag --bail to bun test. When set, it will stop running
tests after the first failure. This is useful for CI environments where
you want to fail fast.
-->
---
- [x] Documentation or TypeScript types (it's okay to leave the rest
blank in this case)
- [x] Code changes
### How did you verify your code works?
<!-- **For code changes, please include automated tests**. Feel free to
uncomment the line below -->
<!-- I wrote automated tests -->
<!-- If JavaScript/TypeScript modules or builtins changed:
- [ ] I included a test for the new code, or existing tests cover it
- [ ] I ran my tests locally and they pass (`bun-debug test
test-file-name.test`)
-->
<!-- If Zig files changed:
- [ ] I checked the lifetime of memory allocated to verify it's (1)
freed and (2) only freed when it should be
- [ ] I included a test for the new code, or an existing test covers it
- [ ] JSValue used outside of the stack is either wrapped in a
JSC.Strong or is JSValueProtect'ed
- [ ] I wrote TypeScript/JavaScript tests and they pass locally
(`bun-debug test test-file-name.test`)
-->
<!-- If new methods, getters, or setters were added to a publicly
exposed class:
- [ ] I added TypeScript types for the new methods, getters, or setters
-->
<!-- If dependencies in tests changed:
- [ ] I made sure that specific versions of dependencies are used
instead of ranged or tagged versions
-->
<!-- If a new builtin ESM/CJS module was added:
- [ ] I updated Aliases in `module_loader.zig` to include the new module
- [ ] I added a test that imports the module
- [ ] I added a test that require() the module
-->
tests (bad currently)
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan-conway@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
### What does this PR do?
in the name
### How did you verify your code works?
tests, but using ci to see if anything else broke
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- Fixes a panic: "exact division produced remainder" that occurs when
reading files with odd number of bytes using utf16le/ucs2 encoding
- The crash happened in `encoding.zig:136` when
`std.mem.bytesAsSlice(u16, input)` was called on a byte slice with odd
length
- Fixed by properly checking for odd-length input and truncating to the
nearest even length
## Test plan
- Added regression tests in
`test/regression/issue/utf16-encoding-crash.test.ts`
- Tests verify that reading files with odd byte counts doesn't crash
- Tests verify correct truncation behavior matches Node.js expectations
- Verified edge cases (0, 1 byte inputs) return empty strings
## Root Cause
The original code checked `if (input.len / 2 == 0)` which only caught 0
and 1-byte inputs, but `std.mem.bytesAsSlice(u16, input)` panics on any
odd-length input (3, 5, 7, etc. bytes).
## Fix Details
- Changed condition to check `input.len % 2 != 0` for any odd length
- Truncate odd-length inputs to the nearest even length for valid UTF-16
processing
- Handle edge cases by returning empty string for 0 or 1-byte inputs
🤖 Generated with [Claude Code](https://claude.ai/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>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
### What does this PR do?
Support sqlite in the Bun.sql API
Fixes#18951Fixes#19701
### How did you verify your code works?
tests
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
## Summary
- Fixes a crash where invalid slice bounds caused a panic with message:
"start index N is larger than end index M"
- The issue occurred in `js_lexer.zig:767` when calculating string
literal content slice bounds
- Adds proper bounds checking to prevent slice bounds violations
- Includes regression test to prevent future occurrences
## Root Cause
The crash happened when `suffix_len` was larger than `lexer.end`,
causing the calculation `lexer.end - suffix_len` to result in a value
smaller than the `base` position. This created invalid slice bounds like
`[114..113]`.
## Solution
Added bounds checking to ensure:
1. `end_pos` is calculated safely: `if (lexer.end >= suffix_len)
lexer.end - suffix_len else lexer.end`
2. `slice_end` is always >= `base`: `@max(base, end_pos)`
## Test Plan
- [x] Added regression test in
`test/regression/issue/jsx-template-string-crash.test.ts`
- [x] Test verifies no crashes occur with JSX template string patterns
- [x] Verified normal template string functionality still works
- [x] All tests pass
🤖 Generated with [Claude Code](https://claude.ai/code)
---------
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
Fixes namespace import objects inheriting from `Object.prototype`,
preventing prototype pollution and ensuring ES specification compliance.
```js
import * as mod from './mod.mjs'
Object.prototype.foo = function() {
console.log('hello');
}
mod.foo(); // This should throw, but succeeded before
```
original report: https://x.com/sapphi_red/status/1957843865722863876
### How did you verify your code works?
I added a test that verifies:
- `mod.maliciousFunction()` throws when
`Object.prototype.maliciousFunction` is added (prevents pollution)
- `__esModule` property still works
- Original exports remain accessible
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
## Summary
Fixes a critical segmentation fault crash occurring during NAPI
finalizer cleanup when finalizers trigger GC operations. This crash was
reported with `node-sqlite3` and other NAPI modules during process exit.
## Root Cause
The crash was caused by **iterator invalidation** in
`napi_env__::cleanup()`:
1. Range-based for loop iterates over `m_finalizers`
(std::unordered_set)
2. `boundFinalizer.call(this)` executes finalizer callbacks
3. Finalizers can trigger JavaScript execution and GC operations
4. GC can add/remove entries from `m_finalizers` during iteration
5. **Iterator invalidation** → undefined behavior → segfault
## Solution
Added `JSC::DeferGCForAWhile deferGC(m_vm)` scope during entire
finalizer cleanup to prevent any GC operations from occurring during
iteration.
### Why This Approach?
- **Addresses root cause**: Prevents GC entirely during critical section
- **Simple & safe**: One-line RAII fix using existing JSC patterns
- **Minimal impact**: Only affects process cleanup (not runtime
performance)
- **Proven pattern**: Already used elsewhere in Bun's codebase
- **Better than alternatives**: Cleaner than Node.js manual iterator
approach
## Testing
Added comprehensive test (`test_finalizer_iterator_invalidation.c`) that
reproduces the crash by:
- Creating finalizers that trigger GC operations
- Forcing JavaScript execution during finalization
- Allocating objects that can trigger more GC
- Calling process exit to trigger finalizer cleanup
**Before fix**: Segmentation fault
**After fix**: Clean exit ✅
## Files Changed
- `src/bun.js/bindings/napi.h`: Core fix + include
- `test/napi/napi-app/test_finalizer_iterator_invalidation.c`: Test
addon
- `test/napi/napi-app/binding.gyp`: Build config for test addon
- `test/regression/issue/napi-finalizer-crash.test.ts`: Integration test
## Test Plan
- [x] Reproduces original crash without fix
- [x] Passes cleanly with fix applied
- [x] Existing NAPI tests continue to pass
- [x] Manual testing with node-sqlite3 scenarios
🤖 Generated with [Claude Code](https://claude.ai/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: Kai Tamkun <kai@tamkun.io>
## Summary
Fixes a crash in `napi_is_exception_pending` that occurs during
environment cleanup when finalizers call this function.
The crash manifested as:
```
panic: Aborted
- napi.h:192: napi_is_exception_pending
- napi.h:516: wrap_cleanup
- napi.h:273: napi_env__::cleanup
```
## Root Cause
Bun's implementation was using `DECLARE_THROW_SCOPE` during cleanup when
JavaScript execution is not safe, and didn't follow Node.js's approach
of avoiding `NAPI_PREAMBLE` for this function.
## Changes Made
1. **Remove `NAPI_PREAMBLE_NO_THROW_SCOPE`** - Node.js explicitly states
this function "must execute when there is a pending exception"
2. **Use `DECLARE_CATCH_SCOPE`** instead of `DECLARE_THROW_SCOPE` for
safety during cleanup
3. **Add safety check** `!env->isFinishingFinalizers()` before accessing
VM
4. **Add `napi_clear_last_error` function** to match Node.js
implementation
5. **Use `napi_clear_last_error`** instead of `napi_set_last_error` for
consistent behavior
## Test Plan
Created comprehensive test that:
- ✅ **Reproduces the original crash scenario** (finalizers calling
`napi_is_exception_pending`)
- ✅ **Verifies it no longer crashes in Bun**
- ✅ **Confirms behavior matches Node.js exactly**
### Test Results
**Before fix:** Would crash with `panic: Aborted` during cleanup
**After fix:**
```
Testing napi_is_exception_pending behavior...
1. Testing basic napi_is_exception_pending:
Status: 0 (should be 0 for napi_ok)
Result: false (should be false - no exception pending)
2. Testing with pending exception:
Exception was thrown as expected: Test exception
3. Testing finalizer scenario (the crash case):
Creating object with finalizer that calls napi_is_exception_pending...
Objects created. Forcing garbage collection...
Garbage collection completed.
napi_is_exception_pending in finalizer: status=0, result=false
[...5 finalizers ran successfully...]
SUCCESS: napi_is_exception_pending works correctly in all scenarios!
```
**Node.js comparison:** Identical output and behavior confirmed.
## Impact
- **Fixes crashes** in native addons that call
`napi_is_exception_pending` in finalizers
- **Improves Node.js compatibility** by aligning implementation approach
- **No breaking changes** - only fixes crash scenario, normal usage
unchanged
The fix aligns Bun's NAPI implementation with Node.js's proven approach
for safe exception checking during environment cleanup.
🤖 Generated with [Claude Code](https://claude.ai/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>
## Summary
Fixes a panic that occurred when parsing malformed integrity data in
lockfiles. The issue was in `integrity.zig` where base64 decoding
attempted to write more bytes than the fixed-size digest buffer could
hold, causing `panic: index out of bounds: index 64, len 64`.
## Root Cause
The `Integrity.parse()` function tried to decode base64 data into a
fixed 64-byte buffer without validating that the decoded size wouldn't
exceed the buffer capacity. When malformed or oversized base64 integrity
strings were encountered in lockfiles, this caused an out-of-bounds
write.
## Fix
Added proper bounds checking in `src/install/integrity.zig`:
- Validates expected digest length before decoding
- Checks decoded size against buffer capacity using `calcSizeForSlice()`
- Only decodes into appropriately sized buffer slice based on hash
algorithm
- Returns `unknown` tag for malformed data instead of panicking
## Test Plan
- [x] Verified release binary crashes with malformed integrity data
- [x] Verified debug build with fix handles malformed data gracefully
- [x] Added comprehensive regression tests for all hash types (sha1,
sha256, sha384, sha512)
- [x] Confirmed normal lockfile parsing continues to work correctly
- [x] Tests pass: `bun bd test
test/regression/issue/integrity-base64-bounds-check.test.ts`
## Before/After
**Before**: `panic: index out of bounds: index 64, len 64`
**After**: Graceful handling with warning about malformed integrity data
🤖 Generated with [Claude Code](https://claude.ai/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>
## Summary
This PR adds a new `--compile-argv` option to `bun build --compile` that
allows developers to embed runtime arguments into standalone
executables. The specified arguments are stored in the executable
metadata during compilation and provide **dual functionality**:
1. **🔧 Actually processed by Bun runtime** (like passing them on command
line)
2. **📊 Available in `process.execArgv`** (for application inspection)
This means flags like `--user-agent`, `--smol`, `--max-memory` will
actually take effect AND be visible to your application!
## Motivation & Use Cases
### 1. **Global User Agent for Web Scraping**
Perfect for @thdxr's opencode use case - the user agent actually gets
applied:
```bash
# Compile with custom user agent that ACTUALLY works
bun build --compile --compile-argv="--user-agent='OpenCode/1.0'" ./scraper.ts --outfile=opencode
# The user agent is applied by Bun runtime AND visible in execArgv
./opencode # All HTTP requests use the custom user agent!
```
### 2. **Memory-Optimized Builds**
Create builds with actual runtime memory optimizations:
```bash
# Compile with memory optimization that ACTUALLY takes effect
bun build --compile --compile-argv="--smol --max-memory=512mb" ./app.ts --outfile=app-optimized
# Bun runtime actually runs in smol mode with memory limit
```
### 3. **Performance & Debug Builds**
Different builds with different runtime characteristics:
```bash
# Production: optimized for memory
bun build --compile --compile-argv="--smol --gc-frequency=high" ./app.ts --outfile=app-prod
# Debug: with inspector enabled
bun build --compile --compile-argv="--inspect=0.0.0.0:9229" ./app.ts --outfile=app-debug
```
### 4. **Security & Network Configuration**
Embed security settings that actually apply:
```bash
# TLS and network settings that work
bun build --compile --compile-argv="--tls-min-version=1.3 --dns-timeout=5000" ./secure-app.ts
```
## How It Works
### Dual Processing Architecture
The implementation provides both behaviors:
```bash
# Compiled with: --compile-argv="--smol --user-agent=Bot/1.0"
./my-app --config=prod.json
```
**What happens:**
1. **🔧 Runtime Processing**: Bun processes `--smol` and
`--user-agent=Bot/1.0` as if passed on command line
2. **📊 Application Access**: Your app can inspect these via
`process.execArgv`
```javascript
// In your compiled application:
// 1. The flags actually took effect:
// - Bun is running in smol mode (--smol processed)
// - All HTTP requests use Bot/1.0 user agent (--user-agent processed)
// 2. You can also inspect what flags were used:
console.log(process.execArgv); // ["--smol", "--user-agent=Bot/1.0"]
console.log(process.argv); // ["./my-app", "--config=prod.json"]
// 3. Your application logic can adapt:
if (process.execArgv.includes("--smol")) {
console.log("Running in memory-optimized mode");
}
```
### Implementation Details
1. **Build Time**: Arguments stored in executable metadata
2. **Runtime Startup**:
- Arguments prepended to actual argv processing (so Bun processes them)
- Arguments also populate `process.execArgv` (so app can inspect them)
3. **Result**: Flags work as if passed on command line + visible to
application
## Example Usage
```bash
# User agent that actually works
bun build --compile --compile-argv="--user-agent='MyBot/1.0'" ./scraper.ts --outfile=scraper
# Memory optimization that actually applies
bun build --compile --compile-argv="--smol --max-memory=256mb" ./microservice.ts --outfile=micro
# Debug build with working inspector
bun build --compile --compile-argv="--inspect=127.0.0.1:9229" ./app.ts --outfile=app-debug
# Multiple working flags
bun build --compile --compile-argv="--smol --user-agent=Bot/1.0 --tls-min-version=1.3" ./secure-scraper.ts
```
## Runtime Verification
```javascript
// Check what runtime flags are active
const hasSmol = process.execArgv.includes("--smol");
const userAgent = process.execArgv.find(arg => arg.startsWith("--user-agent="))?.split("=")[1];
const maxMemory = process.execArgv.find(arg => arg.startsWith("--max-memory="))?.split("=")[1];
console.log("Memory optimized:", hasSmol);
console.log("User agent:", userAgent);
console.log("Memory limit:", maxMemory);
// These flags also actually took effect in the runtime!
```
## Changes Made
### Core Implementation
- **Arguments.zig**: Added `--compile-argv <STR>` flag with validation
- **StandaloneModuleGraph.zig**: Serialization/deserialization for
`compile_argv`
- **build_command.zig**: Pass `compile_argv` to module graph
- **cli.zig**: **Prepend arguments to actual argv processing** (so Bun
processes them)
- **node_process.zig**: **Populate `process.execArgv`** from stored
arguments
- **bun.zig**: Made `appendOptionsEnv()` public for reuse
### Testing
- **expectBundled.ts**: Added `compileArgv` test support
- **compile-argv.test.ts**: Tests verifying dual behavior
## Behavior
### Complete Dual Functionality
```javascript
// With --compile-argv="--smol --user-agent=TestBot/1.0":
// ✅ Runtime flags actually processed by Bun:
// - Memory usage optimized (--smol effect)
// - HTTP requests use TestBot/1.0 user agent (--user-agent effect)
// ✅ Flags visible to application:
process.execArgv // ["--smol", "--user-agent=TestBot/1.0"]
process.argv // ["./app", ...script-args] (unchanged)
```
## Backward Compatibility
- ✅ Purely additive feature - no breaking changes
- ✅ Optional flag - existing behavior unchanged when not used
- ✅ No impact on non-compile builds
## Perfect for @thdxr's Use Case!
```bash
# Compile opencode with working user agent
bun build --compile --compile-argv="--user-agent='OpenCode/1.0'" ./opencode.ts --outfile=opencode
# Results in:
# 1. All HTTP requests actually use OpenCode/1.0 user agent ✨
# 2. process.execArgv contains ["--user-agent=OpenCode/1.0"] for inspection ✨
```
The user agent will actually work in all HTTP requests made by the
compiled executable, not just be visible as metadata!
🚀 Generated with [Claude Code](https://claude.ai/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>
Co-authored-by: Claude <claude@anthropic.ai>