Commit Graph

23 Commits

Author SHA1 Message Date
Marko Vejnovic
e76570f452 feat(ENG-21362): Environment Variables Store (#23930) 2025-10-23 23:08:08 -07:00
Logan Brown
5a82e85876 Fix integer overflow when reading MySQL OK packets (#23993)
### Description
This PR fixes a crash caused by integer underflow in
`OKPacket.decodeInternal`.
Previously, when `read_size` exceeded `packet_size`, the subtraction  
`packet_size - read_size` wrapped around, producing a huge `count` value
passed into `reader.read()`. This led to an integer overflow panic at
runtime.

### What does this PR do
- Added a safe subtraction guard in `decodeInternal` to clamp
`remaining` to `0`
  when `read_size >= packet_size`.  
- Ensures empty or truncated OK packets no longer cause crashes.  
- Behavior for valid packets remains unchanged.

### Impact
Prevents integer overflow panics in MySQL OK packet parsing, improving  
stability when handling short or empty responses (e.g., queries that  
return no rows or minimal metadata).

### How did you verify your code works?
Tested with proof of concept:
https://github.com/Lillious/Bun-MySql-Integer-Overflow-PoC

---------

Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-10-23 13:30:49 -07:00
Ciro Spaciari
1e3e693f4a fix(MySQL) ref and status usage (#23873)
### What does this PR do?
Let MySQL unref when idle and make sure that is behaving like this.
Only set up the timers after all status changes are complete since the
timers rely on the status to determine timeouts, this was causing the
CPU usage spike to 100% (thats why only happened in TLS)
CPU usage it self will be improved in
https://github.com/oven-sh/bun/pull/23700 not in this PR

Fixes: https://github.com/oven-sh/bun/issues/23273
Fixes: https://github.com/oven-sh/bun/issues/23256
### How did you verify your code works?
Test

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-10-20 17:40:48 -07:00
robobun
1c4d8b1c1c fix(sql): throw proper exception for invalid MySQL parameter types (#23839)
## Summary

Fixes a panic that occurred when passing `NumberObject` or
`BooleanObject` as MySQL query parameters.

**Panic message:** `A JavaScript exception was thrown, but it was
cleared before it could be read.`

## Root Cause

The `FieldType.fromJS` function in `src/sql/mysql/MySQLTypes.zig` was
returning `error.JSError` without throwing a JavaScript exception first
for:
- `NumberObject` (created via `new Number(42)`)
- `BooleanObject` (created via `new Boolean(true)`)
- Non-indexable types

This violated the contract that `error.JSError` means "an exception has
already been thrown and is ready to be taken."

## Call Chain

1. User executes `await sql\`SELECT ${new Number(42)} as value\``
2. `FieldType.fromJS()` detects `.NumberObject` and returns
`error.JSError` without throwing
3. Error propagates to `MySQLQuery.runPreparedQuery()`
4. Code checks `hasException()` → returns false (no exception exists!)
5. Calls `mysqlErrorToJS(globalObject, "...", error.JSError)`
6. `mysqlErrorToJS` tries to `takeException(error.JSError)` but there's
no exception
7. **PANIC**

## Fix

The fix throws a proper exception with a helpful message before
returning `error.JSError`:
- `"Cannot bind NumberObject to query parameter. Use a primitive number
instead."`
- `"Cannot bind BooleanObject to query parameter. Use a primitive
boolean instead."`
- `"Cannot bind this type to query parameter"`

## Test Plan

Added regression tests in `test/js/sql/sql-mysql.test.ts`:
- Test passing `NumberObject` as parameter
- Test passing `BooleanObject` as parameter

Both tests verify that a proper error is thrown instead of crashing.

Verified manually with local MySQL server that:
-  NumberObject now throws proper error (was crashing)
-  BooleanObject now throws proper error (was crashing)
-  Primitive numbers still work correctly

🤖 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-20 12:31:08 -07:00
robobun
b867969e2c Remove unused EventLoopTimer.Arm return type (#23765)
## Summary

The `EventLoopTimer.Arm` result from `EventLoopTimer.fire()` was being
ignored at both call sites. This PR removes the unused return type and
simplifies the code.

## Changes

- Changed `EventLoopTimer.fire()` to return `void` instead of `Arm`
- Updated all 15 timer callback functions to return `void`
- Removed the `Arm` type definition
- Simplified the `drainTimers()` loop that was ignoring the return value
- Updated both call sites in `Timer.zig`

## Details

The `.rearm` functionality was unused - timers that need to reschedule
themselves (like DNS resolver) handle this by calling
`addTimer()`/`update()` directly rather than relying on the return
value.

This change removes:
- The `Arm` union enum type (3 lines)
- All `return .disarm` and `return .{ .rearm = ... }` statements
- The switch statement in `drainTimers()` that did nothing with the
return value

Net result: **-58 lines** of dead code removed.

## Testing

- [x] Bun builds successfully with `bun bd`

🤖 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-18 17:04:47 -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
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
Ciro Spaciari
55f8e8add3 fix(Bun.SQL) time should be represented as a string and date as a time (#23193)
### What does this PR do?
Time should be represented as HH:MM:SS or HHH:MM:SS string
### How did you verify your code works?
Test

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-10-02 19:00:14 -07:00
Meghan Denny
51ce3bc269 [publish images] ci: ensure tests that require docker have it available (#22781) 2025-09-25 19:03:22 -07:00
Ciro Spaciari
d85207f179 fix(Bun.SQL) fix MySQL execution on windows (#22696)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/22695
Fixes https://github.com/oven-sh/bun/issues/22654

### How did you verify your code works?
Added mysql:9 + run mysql tests on windows

<img width="1035" height="708"
alt="489727987-3cca2da4-0ff8-4b4a-b5be-9fbdd1c9862d"
src="https://github.com/user-attachments/assets/02c6880d-547e-43b5-8af8-0b7c895c6166"
/>
2025-09-17 08:46:23 -07:00
Ciro Spaciari
beea7180f3 refactor(MySQL) (#22619)
### What does this PR do?

### How did you verify your code works?

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-13 14:52:19 -07:00
Jarred Sumner
e1505b7143 Use JSC::Integrity:: auditCellFully in bindings (#22538)
### What does this PR do?

### How did you verify your code works?
2025-09-10 00:31:54 -07:00
taylor.fish
edf13bd91d Refactor BabyList (#22502)
(For internal tracking: fixes STAB-1129, STAB-1145, STAB-1146,
STAB-1150, STAB-1126, STAB-1147, STAB-1148, STAB-1149, STAB-1158)

---------

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: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-09 20:41:10 -07:00
Ciro Spaciari
b79bbfe289 fix(Bun.SQL) fix SSLRequest (#22378)
### What does this PR do?
Fixes https://github.com/oven-sh/bun/issues/22312
Fixes https://github.com/oven-sh/bun/issues/22313

The correct flow for TLS handshaking is:

Server sending
[Protocol::Handshake](https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_packets_protocol_handshake.html)
Client replying with
[Protocol::SSLRequest:](https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_packets_protocol_ssl_request.html)
The usual SSL exchange leading to establishing SSL connection
Client sends
[Protocol::HandshakeResponse:](https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase_packets_protocol_handshake_response.html)

<img width="460" height="305" alt="Screenshot 2025-09-03 at 15 02 25"
src="https://github.com/user-attachments/assets/091bbc54-75bc-44ac-98b8-5996e8d69ed8"
/>

Source:
https://dev.mysql.com/doc/dev/mysql-server/8.4.5/page_protocol_connection_phase.html

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

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-03 18:59:15 -07:00
Ciro Spaciari
a34e10db53 fix(Bun.SQL) handle MySQL Int24 (#22241)
### What does this PR do?
handle Int24 to be numbers
### How did you verify your code works?
tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-29 17:03:26 -07:00
Ciro Spaciari
1085908386 fix(Bun.SQL) MYSQL fix old auth and auth switch + add lastInsertRowid and affectedRows (#22132)
### What does this PR do?

add `lastInsertRowid` (matching SQLite)
add `affectedRows`
fix `mysql_native_password` deprecated authentication
fix AuthSwitch
Fixes:
https://github.com/oven-sh/bun/issues/22178#issuecomment-3228716080
### How did you verify your code works?
tests

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-08-29 01:03:17 -07:00
Ciro Spaciari
a56488f221 fix(Bun.SQL) handle better BIT(1) in MySQL (#22224)
### What does this PR do?
Fix handling BIT(1) and BIT(N) on binary protocol and text protocol, now
behavior is consistent
### How did you verify your code works?
Tests
2025-08-28 19:14:53 -07:00
Jarred Sumner
fe8f8242fd Make BoundedArray more compact, shrink Data in sql from 32 bytes to 24 bytes (#22210)
### What does this PR do?

- Instead of storing `len` in `BoundedArray` as a `usize`, store it as
either a `u8` or ` u16` depending on the `buffer_capacity`
- Copy-paste `BoundedArray` from the standard library into Bun's
codebase as it was removed in
https://github.com/ziglang/zig/pull/24699/files#diff-cbd8cbbc17583cb9ea5cc0f711ce0ad447b446e62ea5ddbe29274696dce89e4f
and we will probably continue using it

### How did you verify your code works?

Ran `bun run zig:check`

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: taylor.fish <contact@taylor.fish>
2025-08-28 17:34:35 -07:00
Ciro Spaciari
196182f8ec fix(Bun.SQL) fix MySQL by not converting tinyint to bool (#22159)
### 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>
2025-08-26 17:58:08 -07:00
taylor.fish
437e15bae5 Replace catch bun.outOfMemory() with safer alternatives (#22141)
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>
2025-08-26 12:50:25 -07:00
Ciro Spaciari
26c0f324f8 improve(MySQL) optimize queue to skip running queries (#22136)
### What does this PR do?
optimize advance method
after this optimizations
100k req the query bellow in 1 connection takes 792ms instead of 6s
```sql
SELECT CAST(1 AS UNSIGNED) AS x
```
1mi req of the query bellow with 10 connections takes 57.41s - 62.5s
instead of 162.50s, mysql2 takes 1516.94s for comparison
```sql
SELECT * FROM users_bun_bench LIMIT 100
```

### How did you verify your code works?
Tested and benchmarked + CI
2025-08-25 21:12:12 -07:00
Ciro Spaciari
ecbf103bf5 feat(MYSQL) Bun.SQL mysql support (#21968)
### 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>
2025-08-21 15:28:15 -07:00