Skip to content

Rewrite the uSockets core in Rust - #34037

Open
Jarred-Sumner wants to merge 45 commits into
mainfrom
claude/usockets-rust-rewrite
Open

Rewrite the uSockets core in Rust#34037
Jarred-Sumner wants to merge 45 commits into
mainfrom
claude/usockets-rust-rewrite

Conversation

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator

What

Rewrites the uSockets C core as a native Rust crate, bun_usockets (src/usockets/), and deletes the C. Everything socket-shaped in the runtime now runs on it: Bun.serve (HTTP + WebSocket via uWS), fetch and the HTTP client thread, Bun.listen/Bun.connect, node:net/node:tls/node:http, the WebSocket client, Postgres/MySQL/Valkey, Bun.spawn IPC, Bun.udpSocket/node:dgram, and DNS-backed connects.

Deleted: packages/bun-usockets/src/{bsd,loop,socket,context,udp,fault_inject}.c, eventing/, crypto/openssl.c, crypto/sni_tree.cpp (~11.4k lines of C), plus the bun_uws_sys/bun_uws layout-mirror crates (~9.5k lines). Survivors: quic.c (lsquic glue), the root-cert data tables, and the uWS C++ layer.

Design

Memory model: generational slabs, no relocation, reclaimable high-water

Each loop owns chunked slabs of socket slots (256 slots per mmap-reserved chunk; separate size classes so uWS kinds keep their ext data contiguous with the header, exactly like the C's single-allocation layout). Slot addresses are stable for the loop's lifetime. Every externally stored socket reference is a 16-byte SocketRef { ptr, generation }; each operation validates the generation with one load+compare, and a stale handle behaves like today's detached socket — every method is a safe no-op. Use-after-free through a socket handle is impossible by construction, not by review.

Reclamation: when a chunk empties, its pages are decommitted with MADV_DONTNEED (MEM_RESET on Windows) — RSS returns to the OS while the address range stays mapped, so a stale handle's validation read faults in a zero page (generation 0 never matches). A per-chunk epoch, stored outside the decommittable memory and packed into the u64 generation's high bits, makes handles from before a decommit permanently invalid, killing the ABA reuse case. Hysteresis keeps the most-recently-emptied chunk committed so churn at a chunk boundary doesn't thrash. Loops fully release their reservations at teardown, so worker churn doesn't accumulate address space.

Close is a two-phase protocol (unchanged from the C, now type-enforced): close unlinks onto the loop's closed list immediately; the generation bumps and the slot returns to the free list only in the tick postlude. That deferred window is what makes re-entrant closes from user JS callbacks survivable, and it's now the only death path.

Dispatch: const tables, zero dynamic dispatch, zero lazy init

Event dispatch is: kernel udata → generation check → one indirect call through a per-kind vtable in .rodata. The kind→vtable and kind→owner-ops tables are fully const-initialized statics assembled in the one crate that sees every protocol type, reached by the core through a link-time extern "Rust" safe static — no registration calls, no OnceLock, no dyn anywhere in the crate. A new socket kind that isn't wired into the table is a compile error (array shape), not a first-dispatch panic. The generation check also closes a real C bug: a stale kernel event for a recycled poll slot now resolves to a dead slot and is dropped (the C had a narrow stale-udata window after zero-event resize).

Safe consumer interface

Consumers implement a Protocol trait whose handlers receive &Owner (interior-mutable) plus the generation-checked handle. The dispatch trampoline — written once, inside the unsafe jail — takes a strong ref on the owner before invoking any handler and drops it after, so re-entrant JS can no longer free a connection object out from under its own callback. That guarantee deletes the ref-guard/raw-pointer discipline every consumer used to hand-roll: socket-lifecycle unsafe in the migrated consumers (HTTP client, SQL drivers, Valkey, WS client, IPC, UDP, Bun.listen/connect) is now zero. The core also owns terminal ref release exactly-once on every path, including silent SEMI_SOCKET closes that previously required per-consumer compensation code.

All unsafe in the crate is jailed in src/usockets/unsafe_core/ (slab, syscall edges, FFI, trampolines); the rest — loop tick, TLS state machine, timeouts, UDP, dispatch policy — is compiler-enforced safe (deny(unsafe_code)). Outside the jail there are two one-line unsafe blocks.

One event loop abstraction

File polls (fd watchers, process reaping via EVFILT_PROC, machport wakeups, memory-pressure) previously formed a parallel poll universe with raw epoll_ctl/kevent calls, a tagged-pointer udata convention, and a dispatch back-channel through the loop's ready_polls array. They now register through the same generational registry as sockets, with the same owner-held-across-callback guarantee. No epoll_ctl/kevent exists outside src/usockets/backend/ (per-thread queues like the watcher and the IO request loop keep their own kernel queues by design).

TLS

The TLS layer targets the official vendored bssl-sys bindings instead of hand-written externs. Ciphertext staging is loop-shared — one batch buffer and one spill slot per loop, O(1) memory regardless of connection count, same 16KB-record/128KB-flush thresholds as the C — with the two things that made the C version fragile fixed in the types: the buffer owner is a generational handle (can't dangle), and the save/restore re-entrancy protocol around JS callbacks running inside handshakes (ALPN/SNI) is an RAII scope guard. Sockets never relocate on upgradeTLS: adoption restamps the kind in place, deleting both the realloc+memcpy per WebSocket upgrade and the "callback must return the possibly-moved pointer" contract.

The C++ boundary

The surviving uWS C++ layer calls Rust through a minimal extern "C" surface (cabi.rs, ~63 functions) sized to exactly the symbols it uses. Struct-field pokes in the C++ were replaced with accessors so us_socket_t/us_loop_t are fully opaque to C++; only us_socket_group_t remains public repr(C) (uWS embeds it by value). Buffer args are length-checked at the boundary.

Approach

The C's behavior was extracted into numbered rules before any code was written — the loop tick sequence, poll-layer semantics per backend, socket lifecycle, write path, timeout wheels, connect/happy-eyeballs, TLS handshake/shutdown ordering — and the implementation was reviewed rule-by-rule against them. Those rules ship as crate docs (src/usockets/docs/), and code comments cite them by number. Everything perf-relevant carries over exactly: epoll_pwait2 with the ENOSYS latch, kevent64 changelists, sweep deadlines folded into the poll timeout (no timer fd), low-priority handshake parking (5/tick), corking, ENOBUFS/ENOMEM-as-would-block, the close-code trichotomy (close_notify / RST / fast-shutdown), half-open, sendmmsg/recvmmsg UDP batching. Known C quirks are ported verbatim and listed in docs/semantics.md rather than silently fixed; the handful of deliberate deviations (no relocation, generation-checked stale events, core-owned SEMI_SOCKET ref release) are documented in docs/design.md.

Testing

  • Full subsystem sweep on the debug build: socket (incl. a 2048-cycle GC + upgradeTLS stress), udp/dgram, websocket server+client, fetch, serve, spawn IPC, node net/tls/http, valkey — every failure retested solo or against a pre-rewrite debug build and matched the pre-existing set. The websocket publish suite goes 31/31 here vs 11 failures on the pre-rewrite binary.
  • New tests: syscall fault-injection over the rewritten hooks, happy-eyeballs cancel loops, slab unit tests (address stability, stale-handle-after-decommit safety, epoch ABA) run under Miri.
  • cargo check clean on all 10 cross-targets, including the Windows winsock layer; first clean --all-targets workspace check.
  • End-to-end scripts driving the debug binary across every surface above, including tls.connect({socket}) over a live socket and worker loop teardown.

On-box debug-build perf signals (proper benchmarks to follow): websocket 300k-echo 33.4s vs 35.4s pre-rewrite; the pipe-leak RSS test measures 121–159MB vs 240MB pre-rewrite.

… MADV reclamation, unified polls, loop-shared TLS spill
Replaces the C socket core with a Rust crate: generational slab-backed
sockets (stale handles are safe no-ops), all unsafe jailed in one audited
module, loop-shared TLS staging over build-time bssl-sys bindings, const
link-time dispatch tables, and a unified poll registry for sockets and
file polls. Consumers migrate to a safe callback interface where the core
holds the owner alive across dispatch. Deletes ~21k lines of C and Rust
layout mirrors; semantics are parity-ported and documented in
src/usockets/docs/.
Ports the deleted C Windows branches: nonblocking connect via FIONBIO,
WSAEWOULDBLOCK mapping to the shared would-block convention, CRT errno
translation, SetHandleInformation no-inherit, SIO_UDP_CONNRESET/NETRESET
off for UDP, closesocket teardown.
@robobun

robobun commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator
Updated 2:42 PM PT - Jul 13th, 2026

@Jarred-Sumner, your commit b061f12 has 2 failures in Build #72498 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 34037

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

bun-34037 --bun

… build-time bindgen

CI builders don't carry bindgen/libclang. Bindings for all 12 targets are
committed and selected by build.rs per TARGET; regenerate.sh refreshes them
on BoringSSL bumps, with the pinned-commit stamp verified at both configure
and cargo time so a stale copy fails loudly.
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR replaces the C/C++ uSockets implementation (packages/bun-usockets, packages/bun-uws) with a new Rust crate bun_usockets plus a bun_uws_shim compatibility crate, rewires the BoringSSL bindings build to use pre-generated bindings, and migrates all Rust consumer crates (event_loop, http, http_jsc, io, jsc, runtime, sql_jsc, spawn) from bun_uws/bun_uws_sys to the new crates, introducing protocol-v2 owner-ref dispatch, generation-checked socket handles, and a poll registry.

Changes

uSockets Rust rewrite

Layer / File(s) Summary
Build tooling and native glue
Cargo.toml, scripts/build/*, patches/boringssl/*, packages/bun-usockets/..., packages/bun-uws/...
Workspace manifests swap bun_uws/bun_uws_sys for bun_usockets/bun_uws_shim; BoringSSL bindings build switches to committed pre-generated bindings; remaining C headers/quic.c adopt the new C ABI.
bun_usockets core
src/usockets/{backend,cabi.rs,connecting.rs,dispatch.rs,fault.rs,group.rs,handle.rs,kind.rs,lib.rs,loop_,protocol.rs,socket.rs,udp.rs,write.rs,docs}/*
New Rust crate implementing the loop, dispatch/protocol tables, socket handles, groups, connecting-socket state machine, UDP, write path, and fault injection.
bun_usockets TLS engine
src/usockets/tls/*, src/usockets/tls/bssl_bindings/*
Per-socket TLS context/SNI/state engine built on BoringSSL bindings.
bun_usockets unsafe_core
src/usockets/unsafe_core/*
Confined unsafe FFI/syscall boundary: slab allocator, ext access, io syscalls, poll-access edges, BoringSSL FFI, trampolines.
bun_uws_shim crate
src/uws_shim/*
New crate exposing App/Response/Request/WebSocket/H3/QUIC wrappers over bun_usockets for C++ consumers.
Consumer migrations
src/event_loop/*, src/http/*, src/http_jsc/*, src/io/*, src/install/*, src/jsc/*, src/runtime/*, src/spawn/*, src/sql_jsc/*
All consumer crates rewired from bun_uws/bun_uws_sys to bun_usockets/bun_uws_shim, including protocol-v2 dispatch, IPC/ref-counting refactors, an HTTPContext owner-based dispatch model, and a napi ThreadSafeFunction dead-event-loop guard.
Legacy trimming and tests
src/uws_sys/libuwsockets.cpp, test/js/*, test/napi/*
Removes now-unused C++ helpers and adds fault-injection/stress/stale-timer regression tests plus a napi orphaned-threadsafe-function test.

Possibly related PRs

  • oven-sh/bun#33359: Removes the old epoll/kqueue event-loop C code that this PR's Rust rewrite fully replaces.
  • oven-sh/bun#33935: Both PRs update src/event_loop/SpawnSyncEventLoop.rs Windows timer setup around uv_update_time.
  • oven-sh/bun#33952: Both PRs modify the same test/bundler/native-plugin.test.ts crash-reporting test path.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: a Rust rewrite of the uSockets core.
Description check ✅ Passed The description is detailed and covers what changed and how it was verified, though it uses non-template headings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

Comment thread scripts/glob-sources.ts
Comment thread scripts/glob-sources.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/event_loop/SpawnSyncEventLoop.rs`:
- Around line 379-389: Reuse the existing uv_loop local from the timer
initialization block when calling libuv::uv_update_time, instead of recomputing
self.uws_loop().uv_loop.cast(). Keep the existing safety context and timer
behavior unchanged.

In `@src/usockets/tls/context.rs`:
- Around line 143-175: The X509 error-code mapping is duplicated between
x509_error_code and the state.rs variant. Make the state.rs helper delegate to
x509_error_code and convert its returned CStr with as_ptr(), preserving the
existing state.rs return type and leaving a single mapping source of truth.

In `@src/uws_shim/App.rs`:
- Around line 143-163: Deduplicate the publish entry points: update either
publish_with_options or publish to delegate to the other instead of
independently calling c::uws_publish, while preserving the existing arguments
and SendStatus behavior. Apply the same consolidation to the corresponding
implementation around the second referenced method, and remove the now-redundant
byte-identical logic.

In `@src/uws_shim/BodyReaderMixin.rs`:
- Around line 156-207: Extract the duplicated body accumulation logic from
on_data into a shared helper, such as append_chunk, that performs the
MAX_BODY_SIZE check, try_reserve, and extend_from_slice operations and returns
the existing errors. Replace both the non-last branch and the last branch’s
non-empty accumulator sequence with calls to this helper, preserving their
current ownership and response-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 547e73f9-2269-4244-9d1c-2bbbbdab8b56

📥 Commits

Reviewing files that changed from the base of the PR and between 2e2230a and f2c43af.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (252)
  • .gitignore
  • Cargo.toml
  • packages/bun-usockets/src/bsd.c
  • packages/bun-usockets/src/context.c
  • packages/bun-usockets/src/crypto/openssl.c
  • packages/bun-usockets/src/crypto/root_certs.cpp
  • packages/bun-usockets/src/crypto/sni_tree.cpp
  • packages/bun-usockets/src/eventing/epoll_kqueue.c
  • packages/bun-usockets/src/eventing/libuv.c
  • packages/bun-usockets/src/fault_inject.c
  • packages/bun-usockets/src/internal/eventing/epoll_kqueue.h
  • packages/bun-usockets/src/internal/eventing/libuv.h
  • packages/bun-usockets/src/internal/fault_inject.h
  • packages/bun-usockets/src/internal/internal.h
  • packages/bun-usockets/src/internal/loop_data.h
  • packages/bun-usockets/src/internal/networking/bsd.h
  • packages/bun-usockets/src/libusockets_cabi.h
  • packages/bun-usockets/src/loop.c
  • packages/bun-usockets/src/quic.c
  • packages/bun-usockets/src/socket.c
  • packages/bun-usockets/src/udp.c
  • packages/bun-uws/src/App.h
  • packages/bun-uws/src/AsyncSocket.h
  • packages/bun-uws/src/HttpContext.h
  • packages/bun-uws/src/HttpResponse.h
  • patches/boringssl/bssl-sys-prebuilt-bindings.patch
  • scripts/build/bun.ts
  • scripts/build/deps/boringssl.ts
  • scripts/build/rust.ts
  • scripts/build/source.ts
  • scripts/glob-sources.ts
  • src/bun_bin/Cargo.toml
  • src/bun_bin/lib.rs
  • src/dns/lib.rs
  • src/event_loop/AnyEventLoop.rs
  • src/event_loop/Cargo.toml
  • src/event_loop/MiniEventLoop.rs
  • src/event_loop/README.md
  • src/event_loop/SpawnSyncEventLoop.rs
  • src/event_loop/lib.rs
  • src/http/Cargo.toml
  • src/http/CertificateInfo.rs
  • src/http/HTTPCertError.rs
  • src/http/HTTPContext.rs
  • src/http/HTTPThread.rs
  • src/http/ProxyTunnel.rs
  • src/http/h2_client/ClientSession.rs
  • src/http/h3_client/ClientContext.rs
  • src/http/h3_client/ClientSession.rs
  • src/http/h3_client/PendingConnect.rs
  • src/http/h3_client/Stream.rs
  • src/http/h3_client/callbacks.rs
  • src/http/h3_client/encode.rs
  • src/http/lib.rs
  • src/http/ssl_config.rs
  • src/http_jsc/Cargo.toml
  • src/http_jsc/websocket_client.rs
  • src/http_jsc/websocket_client/CppWebSocket.rs
  • src/http_jsc/websocket_client/WebSocketProxyTunnel.rs
  • src/http_jsc/websocket_client/WebSocketUpgradeClient.rs
  • src/install/Cargo.toml
  • src/install/PackageManager/security_scanner.rs
  • src/install/lifecycle_script_runner.rs
  • src/install/resolution.rs
  • src/io/Cargo.toml
  • src/io/PipeReader.rs
  • src/io/PipeWriter.rs
  • src/io/lib.rs
  • src/io/posix_event_loop.rs
  • src/io/windows_event_loop.rs
  • src/jsc/Cargo.toml
  • src/jsc/Debugger.rs
  • src/jsc/FetchHeaders.rs
  • src/jsc/GarbageCollectionController.rs
  • src/jsc/SystemError.rs
  • src/jsc/VirtualMachine.rs
  • src/jsc/bindings/bindings.cpp
  • src/jsc/event_loop.rs
  • src/jsc/ipc.rs
  • src/jsc/lib.rs
  • src/jsc/rare_data.rs
  • src/jsc/virtual_machine_exports.rs
  • src/jsc/web_worker.rs
  • src/react_compiler/lowering/build_hir/mod.rs
  • src/resolver/lib.rs
  • src/router/lib.rs
  • src/runtime/Cargo.toml
  • src/runtime/api/bun/SSLContextCache.rs
  • src/runtime/api/bun/SecureContext.rs
  • src/runtime/api/bun/Terminal.rs
  • src/runtime/api/bun/h2_frame_parser.rs
  • src/runtime/api/bun/js_bun_spawn_bindings.rs
  • src/runtime/api/bun/subprocess.rs
  • src/runtime/api/bun/subprocess/SubprocessPipeReader.rs
  • src/runtime/bake/DevServer.rs
  • src/runtime/bake/dev_server/error_report_request.rs
  • src/runtime/bake/dev_server/hmr_socket.rs
  • src/runtime/bake/dev_server/mod.rs
  • src/runtime/cli/test/parallel/Channel.rs
  • src/runtime/cli/test/parallel/Coordinator.rs
  • src/runtime/cli/test/parallel/Worker.rs
  • src/runtime/cli/test/parallel/runner.rs
  • src/runtime/crypto/CryptoHasher.rs
  • src/runtime/dispatch.rs
  • src/runtime/dns_jsc/dns.rs
  • src/runtime/ffi/ffi_body.rs
  • src/runtime/hw_exports.rs
  • src/runtime/ipc_host.rs
  • src/runtime/jsc_hooks.rs
  • src/runtime/node/node_cluster_binding.rs
  • src/runtime/node/node_net_binding.rs
  • src/runtime/node/node_os.rs
  • src/runtime/server/AnyRequestContext.rs
  • src/runtime/server/FileResponseStream.rs
  • src/runtime/server/FileRoute.rs
  • src/runtime/server/HTMLBundle.rs
  • src/runtime/server/NodeHTTPResponse.rs
  • src/runtime/server/RangeRequest.rs
  • src/runtime/server/RequestContext.rs
  • src/runtime/server/ServerConfig.rs
  • src/runtime/server/ServerWebSocket.rs
  • src/runtime/server/StaticRoute.rs
  • src/runtime/server/WebSocketServerContext.rs
  • src/runtime/server/mod.rs
  • src/runtime/server/server_body.rs
  • src/runtime/shell/IOWriter.rs
  • src/runtime/shell/builtin/yes.rs
  • src/runtime/shell/shell_body.rs
  • src/runtime/socket/Handlers.rs
  • src/runtime/socket/Listener.rs
  • src/runtime/socket/UpgradedDuplex.rs
  • src/runtime/socket/WindowsNamedPipe.rs
  • src/runtime/socket/WindowsNamedPipeContext.rs
  • src/runtime/socket/mod.rs
  • src/runtime/socket/socket_body.rs
  • src/runtime/socket/tls_socket_functions.rs
  • src/runtime/socket/udp_socket.rs
  • src/runtime/socket/uws_dispatch.rs
  • src/runtime/socket/uws_handlers.rs
  • src/runtime/socket/uws_jsc.rs
  • src/runtime/test_runner/diff/diff_match_patch.rs
  • src/runtime/timer/DateHeaderTimer.rs
  • src/runtime/timer/Timer.rs
  • src/runtime/timer/WTFTimer.rs
  • src/runtime/timer/mod.rs
  • src/runtime/valkey_jsc/js_valkey.rs
  • src/runtime/valkey_jsc/mod.rs
  • src/runtime/valkey_jsc/valkey.rs
  • src/runtime/webcore/CookieMap.rs
  • src/runtime/webcore/FileReader.rs
  • src/runtime/webcore/Request.rs
  • src/runtime/webcore/fetch/FetchTasklet.rs
  • src/runtime/webcore/streams.rs
  • src/spawn/Cargo.toml
  • src/spawn/process.rs
  • src/sql_jsc/Cargo.toml
  • src/sql_jsc/jsc.rs
  • src/sql_jsc/mysql/JSMySQLConnection.rs
  • src/sql_jsc/mysql/MySQLConnection.rs
  • src/sql_jsc/postgres/PostgresSQLConnection.rs
  • src/sql_jsc/shared/ConnectionCtorArgs.rs
  • src/usockets/Cargo.toml
  • src/usockets/backend/epoll.rs
  • src/usockets/backend/kqueue.rs
  • src/usockets/backend/libuv.rs
  • src/usockets/backend/mod.rs
  • src/usockets/cabi.rs
  • src/usockets/connecting.rs
  • src/usockets/dispatch.rs
  • src/usockets/docs/cabi.md
  • src/usockets/docs/design.md
  • src/usockets/docs/semantics.md
  • src/usockets/docs/tls.md
  • src/usockets/fault.rs
  • src/usockets/group.rs
  • src/usockets/handle.rs
  • src/usockets/kind.rs
  • src/usockets/lib.rs
  • src/usockets/loop_/mod.rs
  • src/usockets/loop_/poll_registry.rs
  • src/usockets/loop_/tick.rs
  • src/usockets/loop_/timeouts.rs
  • src/usockets/loop_/wakeup.rs
  • src/usockets/protocol.rs
  • src/usockets/socket.rs
  • src/usockets/tls/bssl_bindings/README.md
  • src/usockets/tls/bssl_bindings/regenerate.sh
  • src/usockets/tls/bssl_bindings/wrapper.c
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-apple-darwin.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-linux-android.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-pc-windows-msvc.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-unknown-freebsd.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-unknown-linux-gnu.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-unknown-linux-musl.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-apple-darwin.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-linux-android.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-pc-windows-msvc.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-unknown-freebsd.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-unknown-linux-gnu.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-unknown-linux-musl.rs
  • src/usockets/tls/context.rs
  • src/usockets/tls/mod.rs
  • src/usockets/tls/sni.rs
  • src/usockets/tls/state.rs
  • src/usockets/udp.rs
  • src/usockets/unsafe_core/bssl.rs
  • src/usockets/unsafe_core/deref.rs
  • src/usockets/unsafe_core/ext.rs
  • src/usockets/unsafe_core/ffi.rs
  • src/usockets/unsafe_core/io.rs
  • src/usockets/unsafe_core/mod.rs
  • src/usockets/unsafe_core/poll_access.rs
  • src/usockets/unsafe_core/slab.rs
  • src/usockets/unsafe_core/test_support.rs
  • src/usockets/unsafe_core/trampolines.rs
  • src/usockets/write.rs
  • src/uws_shim/App.rs
  • src/uws_shim/BodyReaderMixin.rs
  • src/uws_shim/Cargo.toml
  • src/uws_shim/Request.rs
  • src/uws_shim/Response.rs
  • src/uws_shim/WebSocket.rs
  • src/uws_shim/h3.rs
  • src/uws_shim/lib.rs
  • src/uws_shim/quic.rs
  • src/uws_shim/quic/Context.rs
  • src/uws_shim/quic/Header.rs
  • src/uws_shim/quic/PendingConnect.rs
  • src/uws_shim/quic/Socket.rs
  • src/uws_shim/quic/Stream.rs
  • src/uws_shim/thunk.rs
  • src/uws_shim/us_socket.rs
  • src/uws_sys/Cargo.toml
  • src/uws_sys/ConnectingSocket.rs
  • src/uws_sys/InternalLoopData.rs
  • src/uws_sys/ListenSocket.rs
  • src/uws_sys/Loop.rs
  • src/uws_sys/SocketContext.rs
  • src/uws_sys/SocketGroup.rs
  • src/uws_sys/SocketKind.rs
  • src/uws_sys/Timer.rs
  • src/uws_sys/lib.rs
  • src/uws_sys/libuwsockets.cpp
  • src/uws_sys/socket.rs
  • src/uws_sys/udp.rs
  • src/uws_sys/us_socket_t.rs
  • src/uws_sys/vtable.rs
  • test/js/bun/net/socket-syscall-fault.test.ts
  • test/js/bun/net/socket.test.ts
  • test/js/node/http/node-http-syscall-fault.test.ts
  • test/js/node/net/connect-autoselectfamily-cancel-loop-fixture.js
  • test/js/node/net/connect-autoselectfamily-stale-timer.test.ts
💤 Files with no reviewable changes (19)
  • src/install/Cargo.toml
  • packages/bun-usockets/src/internal/eventing/libuv.h
  • packages/bun-uws/src/AsyncSocket.h
  • packages/bun-usockets/src/internal/eventing/epoll_kqueue.h
  • packages/bun-usockets/src/context.c
  • packages/bun-usockets/src/internal/loop_data.h
  • packages/bun-usockets/src/internal/fault_inject.h
  • packages/bun-usockets/src/fault_inject.c
  • src/jsc/bindings/bindings.cpp
  • packages/bun-usockets/src/crypto/sni_tree.cpp
  • packages/bun-usockets/src/internal/networking/bsd.h
  • packages/bun-usockets/src/eventing/libuv.c
  • packages/bun-usockets/src/internal/internal.h
  • packages/bun-usockets/src/loop.c
  • packages/bun-usockets/src/eventing/epoll_kqueue.c
  • packages/bun-usockets/src/udp.c
  • packages/bun-usockets/src/bsd.c
  • packages/bun-usockets/src/socket.c
  • src/uws_sys/libuwsockets.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/event_loop/SpawnSyncEventLoop.rs`:
- Around line 379-389: Reuse the existing uv_loop local from the timer
initialization block when calling libuv::uv_update_time, instead of recomputing
self.uws_loop().uv_loop.cast(). Keep the existing safety context and timer
behavior unchanged.

In `@src/usockets/tls/context.rs`:
- Around line 143-175: The X509 error-code mapping is duplicated between
x509_error_code and the state.rs variant. Make the state.rs helper delegate to
x509_error_code and convert its returned CStr with as_ptr(), preserving the
existing state.rs return type and leaving a single mapping source of truth.

In `@src/uws_shim/App.rs`:
- Around line 143-163: Deduplicate the publish entry points: update either
publish_with_options or publish to delegate to the other instead of
independently calling c::uws_publish, while preserving the existing arguments
and SendStatus behavior. Apply the same consolidation to the corresponding
implementation around the second referenced method, and remove the now-redundant
byte-identical logic.

In `@src/uws_shim/BodyReaderMixin.rs`:
- Around line 156-207: Extract the duplicated body accumulation logic from
on_data into a shared helper, such as append_chunk, that performs the
MAX_BODY_SIZE check, try_reserve, and extend_from_slice operations and returns
the existing errors. Replace both the non-last branch and the last branch’s
non-empty accumulator sequence with calls to this helper, preserving their
current ownership and response-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 547e73f9-2269-4244-9d1c-2bbbbdab8b56

📥 Commits

Reviewing files that changed from the base of the PR and between 2e2230a and f2c43af.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (252)
  • .gitignore
  • Cargo.toml
  • packages/bun-usockets/src/bsd.c
  • packages/bun-usockets/src/context.c
  • packages/bun-usockets/src/crypto/openssl.c
  • packages/bun-usockets/src/crypto/root_certs.cpp
  • packages/bun-usockets/src/crypto/sni_tree.cpp
  • packages/bun-usockets/src/eventing/epoll_kqueue.c
  • packages/bun-usockets/src/eventing/libuv.c
  • packages/bun-usockets/src/fault_inject.c
  • packages/bun-usockets/src/internal/eventing/epoll_kqueue.h
  • packages/bun-usockets/src/internal/eventing/libuv.h
  • packages/bun-usockets/src/internal/fault_inject.h
  • packages/bun-usockets/src/internal/internal.h
  • packages/bun-usockets/src/internal/loop_data.h
  • packages/bun-usockets/src/internal/networking/bsd.h
  • packages/bun-usockets/src/libusockets_cabi.h
  • packages/bun-usockets/src/loop.c
  • packages/bun-usockets/src/quic.c
  • packages/bun-usockets/src/socket.c
  • packages/bun-usockets/src/udp.c
  • packages/bun-uws/src/App.h
  • packages/bun-uws/src/AsyncSocket.h
  • packages/bun-uws/src/HttpContext.h
  • packages/bun-uws/src/HttpResponse.h
  • patches/boringssl/bssl-sys-prebuilt-bindings.patch
  • scripts/build/bun.ts
  • scripts/build/deps/boringssl.ts
  • scripts/build/rust.ts
  • scripts/build/source.ts
  • scripts/glob-sources.ts
  • src/bun_bin/Cargo.toml
  • src/bun_bin/lib.rs
  • src/dns/lib.rs
  • src/event_loop/AnyEventLoop.rs
  • src/event_loop/Cargo.toml
  • src/event_loop/MiniEventLoop.rs
  • src/event_loop/README.md
  • src/event_loop/SpawnSyncEventLoop.rs
  • src/event_loop/lib.rs
  • src/http/Cargo.toml
  • src/http/CertificateInfo.rs
  • src/http/HTTPCertError.rs
  • src/http/HTTPContext.rs
  • src/http/HTTPThread.rs
  • src/http/ProxyTunnel.rs
  • src/http/h2_client/ClientSession.rs
  • src/http/h3_client/ClientContext.rs
  • src/http/h3_client/ClientSession.rs
  • src/http/h3_client/PendingConnect.rs
  • src/http/h3_client/Stream.rs
  • src/http/h3_client/callbacks.rs
  • src/http/h3_client/encode.rs
  • src/http/lib.rs
  • src/http/ssl_config.rs
  • src/http_jsc/Cargo.toml
  • src/http_jsc/websocket_client.rs
  • src/http_jsc/websocket_client/CppWebSocket.rs
  • src/http_jsc/websocket_client/WebSocketProxyTunnel.rs
  • src/http_jsc/websocket_client/WebSocketUpgradeClient.rs
  • src/install/Cargo.toml
  • src/install/PackageManager/security_scanner.rs
  • src/install/lifecycle_script_runner.rs
  • src/install/resolution.rs
  • src/io/Cargo.toml
  • src/io/PipeReader.rs
  • src/io/PipeWriter.rs
  • src/io/lib.rs
  • src/io/posix_event_loop.rs
  • src/io/windows_event_loop.rs
  • src/jsc/Cargo.toml
  • src/jsc/Debugger.rs
  • src/jsc/FetchHeaders.rs
  • src/jsc/GarbageCollectionController.rs
  • src/jsc/SystemError.rs
  • src/jsc/VirtualMachine.rs
  • src/jsc/bindings/bindings.cpp
  • src/jsc/event_loop.rs
  • src/jsc/ipc.rs
  • src/jsc/lib.rs
  • src/jsc/rare_data.rs
  • src/jsc/virtual_machine_exports.rs
  • src/jsc/web_worker.rs
  • src/react_compiler/lowering/build_hir/mod.rs
  • src/resolver/lib.rs
  • src/router/lib.rs
  • src/runtime/Cargo.toml
  • src/runtime/api/bun/SSLContextCache.rs
  • src/runtime/api/bun/SecureContext.rs
  • src/runtime/api/bun/Terminal.rs
  • src/runtime/api/bun/h2_frame_parser.rs
  • src/runtime/api/bun/js_bun_spawn_bindings.rs
  • src/runtime/api/bun/subprocess.rs
  • src/runtime/api/bun/subprocess/SubprocessPipeReader.rs
  • src/runtime/bake/DevServer.rs
  • src/runtime/bake/dev_server/error_report_request.rs
  • src/runtime/bake/dev_server/hmr_socket.rs
  • src/runtime/bake/dev_server/mod.rs
  • src/runtime/cli/test/parallel/Channel.rs
  • src/runtime/cli/test/parallel/Coordinator.rs
  • src/runtime/cli/test/parallel/Worker.rs
  • src/runtime/cli/test/parallel/runner.rs
  • src/runtime/crypto/CryptoHasher.rs
  • src/runtime/dispatch.rs
  • src/runtime/dns_jsc/dns.rs
  • src/runtime/ffi/ffi_body.rs
  • src/runtime/hw_exports.rs
  • src/runtime/ipc_host.rs
  • src/runtime/jsc_hooks.rs
  • src/runtime/node/node_cluster_binding.rs
  • src/runtime/node/node_net_binding.rs
  • src/runtime/node/node_os.rs
  • src/runtime/server/AnyRequestContext.rs
  • src/runtime/server/FileResponseStream.rs
  • src/runtime/server/FileRoute.rs
  • src/runtime/server/HTMLBundle.rs
  • src/runtime/server/NodeHTTPResponse.rs
  • src/runtime/server/RangeRequest.rs
  • src/runtime/server/RequestContext.rs
  • src/runtime/server/ServerConfig.rs
  • src/runtime/server/ServerWebSocket.rs
  • src/runtime/server/StaticRoute.rs
  • src/runtime/server/WebSocketServerContext.rs
  • src/runtime/server/mod.rs
  • src/runtime/server/server_body.rs
  • src/runtime/shell/IOWriter.rs
  • src/runtime/shell/builtin/yes.rs
  • src/runtime/shell/shell_body.rs
  • src/runtime/socket/Handlers.rs
  • src/runtime/socket/Listener.rs
  • src/runtime/socket/UpgradedDuplex.rs
  • src/runtime/socket/WindowsNamedPipe.rs
  • src/runtime/socket/WindowsNamedPipeContext.rs
  • src/runtime/socket/mod.rs
  • src/runtime/socket/socket_body.rs
  • src/runtime/socket/tls_socket_functions.rs
  • src/runtime/socket/udp_socket.rs
  • src/runtime/socket/uws_dispatch.rs
  • src/runtime/socket/uws_handlers.rs
  • src/runtime/socket/uws_jsc.rs
  • src/runtime/test_runner/diff/diff_match_patch.rs
  • src/runtime/timer/DateHeaderTimer.rs
  • src/runtime/timer/Timer.rs
  • src/runtime/timer/WTFTimer.rs
  • src/runtime/timer/mod.rs
  • src/runtime/valkey_jsc/js_valkey.rs
  • src/runtime/valkey_jsc/mod.rs
  • src/runtime/valkey_jsc/valkey.rs
  • src/runtime/webcore/CookieMap.rs
  • src/runtime/webcore/FileReader.rs
  • src/runtime/webcore/Request.rs
  • src/runtime/webcore/fetch/FetchTasklet.rs
  • src/runtime/webcore/streams.rs
  • src/spawn/Cargo.toml
  • src/spawn/process.rs
  • src/sql_jsc/Cargo.toml
  • src/sql_jsc/jsc.rs
  • src/sql_jsc/mysql/JSMySQLConnection.rs
  • src/sql_jsc/mysql/MySQLConnection.rs
  • src/sql_jsc/postgres/PostgresSQLConnection.rs
  • src/sql_jsc/shared/ConnectionCtorArgs.rs
  • src/usockets/Cargo.toml
  • src/usockets/backend/epoll.rs
  • src/usockets/backend/kqueue.rs
  • src/usockets/backend/libuv.rs
  • src/usockets/backend/mod.rs
  • src/usockets/cabi.rs
  • src/usockets/connecting.rs
  • src/usockets/dispatch.rs
  • src/usockets/docs/cabi.md
  • src/usockets/docs/design.md
  • src/usockets/docs/semantics.md
  • src/usockets/docs/tls.md
  • src/usockets/fault.rs
  • src/usockets/group.rs
  • src/usockets/handle.rs
  • src/usockets/kind.rs
  • src/usockets/lib.rs
  • src/usockets/loop_/mod.rs
  • src/usockets/loop_/poll_registry.rs
  • src/usockets/loop_/tick.rs
  • src/usockets/loop_/timeouts.rs
  • src/usockets/loop_/wakeup.rs
  • src/usockets/protocol.rs
  • src/usockets/socket.rs
  • src/usockets/tls/bssl_bindings/README.md
  • src/usockets/tls/bssl_bindings/regenerate.sh
  • src/usockets/tls/bssl_bindings/wrapper.c
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-apple-darwin.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-linux-android.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-pc-windows-msvc.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-unknown-freebsd.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-unknown-linux-gnu.rs
  • src/usockets/tls/bssl_bindings/wrapper_aarch64-unknown-linux-musl.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-apple-darwin.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-linux-android.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-pc-windows-msvc.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-unknown-freebsd.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-unknown-linux-gnu.rs
  • src/usockets/tls/bssl_bindings/wrapper_x86_64-unknown-linux-musl.rs
  • src/usockets/tls/context.rs
  • src/usockets/tls/mod.rs
  • src/usockets/tls/sni.rs
  • src/usockets/tls/state.rs
  • src/usockets/udp.rs
  • src/usockets/unsafe_core/bssl.rs
  • src/usockets/unsafe_core/deref.rs
  • src/usockets/unsafe_core/ext.rs
  • src/usockets/unsafe_core/ffi.rs
  • src/usockets/unsafe_core/io.rs
  • src/usockets/unsafe_core/mod.rs
  • src/usockets/unsafe_core/poll_access.rs
  • src/usockets/unsafe_core/slab.rs
  • src/usockets/unsafe_core/test_support.rs
  • src/usockets/unsafe_core/trampolines.rs
  • src/usockets/write.rs
  • src/uws_shim/App.rs
  • src/uws_shim/BodyReaderMixin.rs
  • src/uws_shim/Cargo.toml
  • src/uws_shim/Request.rs
  • src/uws_shim/Response.rs
  • src/uws_shim/WebSocket.rs
  • src/uws_shim/h3.rs
  • src/uws_shim/lib.rs
  • src/uws_shim/quic.rs
  • src/uws_shim/quic/Context.rs
  • src/uws_shim/quic/Header.rs
  • src/uws_shim/quic/PendingConnect.rs
  • src/uws_shim/quic/Socket.rs
  • src/uws_shim/quic/Stream.rs
  • src/uws_shim/thunk.rs
  • src/uws_shim/us_socket.rs
  • src/uws_sys/Cargo.toml
  • src/uws_sys/ConnectingSocket.rs
  • src/uws_sys/InternalLoopData.rs
  • src/uws_sys/ListenSocket.rs
  • src/uws_sys/Loop.rs
  • src/uws_sys/SocketContext.rs
  • src/uws_sys/SocketGroup.rs
  • src/uws_sys/SocketKind.rs
  • src/uws_sys/Timer.rs
  • src/uws_sys/lib.rs
  • src/uws_sys/libuwsockets.cpp
  • src/uws_sys/socket.rs
  • src/uws_sys/udp.rs
  • src/uws_sys/us_socket_t.rs
  • src/uws_sys/vtable.rs
  • test/js/bun/net/socket-syscall-fault.test.ts
  • test/js/bun/net/socket.test.ts
  • test/js/node/http/node-http-syscall-fault.test.ts
  • test/js/node/net/connect-autoselectfamily-cancel-loop-fixture.js
  • test/js/node/net/connect-autoselectfamily-stale-timer.test.ts
💤 Files with no reviewable changes (19)
  • src/install/Cargo.toml
  • packages/bun-usockets/src/internal/eventing/libuv.h
  • packages/bun-uws/src/AsyncSocket.h
  • packages/bun-usockets/src/internal/eventing/epoll_kqueue.h
  • packages/bun-usockets/src/context.c
  • packages/bun-usockets/src/internal/loop_data.h
  • packages/bun-usockets/src/internal/fault_inject.h
  • packages/bun-usockets/src/fault_inject.c
  • src/jsc/bindings/bindings.cpp
  • packages/bun-usockets/src/crypto/sni_tree.cpp
  • packages/bun-usockets/src/internal/networking/bsd.h
  • packages/bun-usockets/src/eventing/libuv.c
  • packages/bun-usockets/src/internal/internal.h
  • packages/bun-usockets/src/loop.c
  • packages/bun-usockets/src/eventing/epoll_kqueue.c
  • packages/bun-usockets/src/udp.c
  • packages/bun-usockets/src/bsd.c
  • packages/bun-usockets/src/socket.c
  • src/uws_sys/libuwsockets.cpp
🛑 Comments failed to post (4)
src/event_loop/SpawnSyncEventLoop.rs (1)

379-389: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor: reuse the already-extracted uv_loop pointer instead of recomputing it.

uv_loop is computed via self.uws_loop().uv_loop.cast::<libuv::Loop>() on line 381 and then the same expression is recomputed on line 389 for uv_update_time. Reusing the local avoids a second &self borrow/FFI-field read for the same value.

♻️ Proposed dedup
             let uv_loop = self.uws_loop().uv_loop.cast::<libuv::Loop>();
             self.uv_timer_mut().expect("just set").init(uv_loop);
+            // Refresh the loop's cached clock using the pointer already extracted above.
+            unsafe { libuv::uv_update_time(uv_loop) };
+            return;
         }
-
-        // Refresh the loop's cached clock: ...
-        unsafe { libuv::uv_update_time(self.uws_loop().uv_loop.cast()) };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/event_loop/SpawnSyncEventLoop.rs` around lines 379 - 389, Reuse the
existing uv_loop local from the timer initialization block when calling
libuv::uv_update_time, instead of recomputing self.uws_loop().uv_loop.cast().
Keep the existing safety context and timer behavior unchanged.
src/usockets/tls/context.rs (1)

143-175: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

x509_error_code table is duplicated verbatim in state.rs.

This 30-entry X509_V_ERR → symbolic-name table is byte-for-byte identical to x509_error_code in src/usockets/tls/state.rs (Lines 1272-1309); the only difference is the return type (&'static CStr here vs *const c_char there). Two copies must be kept in sync when BoringSSL error codes change. Consider making the state.rs variant delegate to this one via .as_ptr() (or share a single table), keeping one source of truth.

As per coding guidelines: "One source of truth ... Never copy a helper or constant table between modules — share or derive it."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/usockets/tls/context.rs` around lines 143 - 175, The X509 error-code
mapping is duplicated between x509_error_code and the state.rs variant. Make the
state.rs helper delegate to x509_error_code and convert its returned CStr with
as_ptr(), preserving the existing state.rs return type and leaving a single
mapping source of truth.

Source: Coding guidelines

src/uws_shim/App.rs (1)

143-163: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

publish_with_options and publish are byte-identical implementations.

Both methods take the same parameters and call c::uws_publish with the same arguments (SSL as i32 and Self::SSL_FLAG are equal by definition). Per repo convention, duplicated logic like this should be collapsed — have one delegate to the other so future changes to the publish call don't silently diverge between the two entry points.

♻️ Suggested dedup
     pub fn publish_with_options(
         &mut self,
         topic: &[u8],
         message: &[u8],
         opcode: Opcode,
         compress: bool,
     ) -> SendStatus {
-        // SAFETY: self is a valid *mut uws_app_t; slices are valid for the call.
-        unsafe {
-            c::uws_publish(
-                SSL as i32,
-                std::ptr::from_mut::<Self>(self).cast::<uws_app_t>(),
-                topic.as_ptr(),
-                topic.len(),
-                message.as_ptr(),
-                message.len(),
-                opcode,
-                compress,
-            )
-        }
+        self.publish(topic, message, opcode, compress)
     }

Based on learnings, this repo's landing-PR guidance states: "If your fix makes two functions byte-identical, delete one."

Also applies to: 323-343

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/uws_shim/App.rs` around lines 143 - 163, Deduplicate the publish entry
points: update either publish_with_options or publish to delegate to the other
instead of independently calling c::uws_publish, while preserving the existing
arguments and SendStatus behavior. Apply the same consolidation to the
corresponding implementation around the second referenced method, and remove the
now-redundant byte-identical logic.
src/uws_shim/BodyReaderMixin.rs (1)

156-207: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Duplicated size-check/reserve/extend block between the "last, non-empty accumulator" and "non-last" branches.

The MAX_BODY_SIZE check + try_reserve + extend_from_slice sequence (lines ~169-177 and ~195-204) is byte-for-byte identical logic repeated twice in the same function. Extracting a shared helper (e.g. fn append_chunk(body: &mut Vec<u8>, chunk: &[u8]) -> Result<(), bun_core::Error>) would remove the duplication and guard against the two copies drifting if the size/OOM policy changes later.

♻️ Suggested extraction
+    fn append_chunk(body: &mut Vec<u8>, chunk: &[u8]) -> Result<(), bun_core::Error> {
+        if body.len().saturating_add(chunk.len()) > MAX_BODY_SIZE {
+            return Err(bun_core::err!(RequestBodyTooLarge));
+        }
+        if body.try_reserve(chunk.len()).is_err() {
+            return Err(bun_core::err!(OutOfMemory));
+        }
+        body.extend_from_slice(chunk);
+        Ok(())
+    }
+
     fn on_data(...) -> Result<(), bun_core::Error> {
         if last {
             let mut body = mem::take(&mut Self::mixin_of(wrap).body);
             resp.clear_on_data();
             if !body.is_empty() {
-                if body.len().saturating_add(chunk.len()) > MAX_BODY_SIZE {
-                    return Err(bun_core::err!(RequestBodyTooLarge));
-                }
-                if body.try_reserve(chunk.len()).is_err() {
-                    return Err(bun_core::err!(OutOfMemory));
-                }
-                body.extend_from_slice(chunk);
+                Self::append_chunk(&mut body, chunk)?;
                 unsafe { Wrap::on_body(wrap, body.as_slice(), resp)? };
             } else {
                 ...
             }
             Ok(())
         } else {
             let body = &mut Self::mixin_of(wrap).body;
-            if body.len().saturating_add(chunk.len()) > MAX_BODY_SIZE {
-                return Err(bun_core::err!(RequestBodyTooLarge));
-            }
-            if body.try_reserve(chunk.len()).is_err() {
-                return Err(bun_core::err!(OutOfMemory));
-            }
-            body.extend_from_slice(chunk);
-            Ok(())
+            Self::append_chunk(body, chunk)
         }
     }

Based on learnings, the repo's landing-PR guidance states: "The second time a multi-line block appears in your diff, extract a named helper and use it at EVERY parallel site."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    fn append_chunk(body: &mut Vec<u8>, chunk: &[u8]) -> Result<(), bun_core::Error> {
        if body.len().saturating_add(chunk.len()) > MAX_BODY_SIZE {
            return Err(bun_core::err!(RequestBodyTooLarge));
        }
        if body.try_reserve(chunk.len()).is_err() {
            return Err(bun_core::err!(OutOfMemory));
        }
        body.extend_from_slice(chunk);
        Ok(())
    }

    fn on_data(
        wrap: *mut Wrap,
        resp: AnyResponse,
        chunk: &[u8],
        last: bool,
    ) -> Result<(), bun_core::Error> {
        if last {
            // Free everything after. Take via the mixin field first — no
            // `&mut Wrap` is live yet, and the temporary `&mut Self` ends at
            // the `;` (before `on_body`, which may heap::take(wrap)).
            let mut body = mem::take(&mut Self::mixin_of(wrap).body);
            resp.clear_on_data();
            if !body.is_empty() {
                Self::append_chunk(&mut body, chunk)?;
                // SAFETY: wrap is the original heap-allocated pointer; the &mut to
                // mixin.body has ended, so on_body receives sole ownership of the
                // allocation and may heap::take it on success.
                unsafe { Wrap::on_body(wrap, body.as_slice(), resp)? };
            } else {
                if chunk.len() > MAX_BODY_SIZE {
                    return Err(bun_core::err!(RequestBodyTooLarge));
                }
                // SAFETY: wrap is the original heap-allocated pointer; the &mut to
                // mixin.body has ended, so on_body receives sole ownership of the
                // allocation and may heap::take it on success.
                unsafe { Wrap::on_body(wrap, chunk, resp)? };
            }
            // `body` drops here
            Ok(())
        } else {
            let body = &mut Self::mixin_of(wrap).body;
            Self::append_chunk(body, chunk)
        }
    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/uws_shim/BodyReaderMixin.rs` around lines 156 - 207, Extract the
duplicated body accumulation logic from on_data into a shared helper, such as
append_chunk, that performs the MAX_BODY_SIZE check, try_reserve, and
extend_from_slice operations and returns the existing errors. Replace both the
non-last branch and the last branch’s non-empty accumulator sequence with calls
to this helper, preserving their current ownership and response-handling
behavior.

Comment thread Cargo.toml
Comment thread Cargo.toml
Comment thread Cargo.toml
@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

@robobun run bun upgrade --canary, download this PR's build artifact, and benchmark express, fastify, and Elysia — this branch vs canary — using oha. Measure req/s, RSS, and latency (p50/p99), and post the results as a table.

@robobun

robobun commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Benchmark results: this branch vs canary

Setup: oha 1.15.0, -z 15s -c 100, 3 runs per combo (best shown), 3s warmup before each run. GET / returning "Hello, World!". Linux x64, Xeon Platinum 8375C (16 vCPU). Versions: express 5.2.1, fastify 5.10.0, elysia 1.4.29.

Note on binaries

No linux-x64 artifact existed for this PR when I started (earlier builds failed at the cpp stage, #72235 was still building), so I built the PR locally with bun run build:release. That profile is non-LTO; the published canary is LTO. Comparing those directly measures LTO, not the rewrite. To isolate the rewrite I also built main@2e2230a81 (this PR's merge-base, same commit as current canary) locally with the same flags.

Same toolchain: main@2e2230a81 vs PR 76786b440 (both local build:release, non-LTO)

Framework Binary req/s (best of 3) p50 p99 RSS Δ req/s
express main 41,369 2.24 ms 4.65 ms 92.8 MB
PR 41,596 2.21 ms 4.77 ms 91.5 MB +0.5%
fastify main 62,619 1.48 ms 3.22 ms 119.1 MB
PR 64,713 1.44 ms 3.12 ms 118.7 MB +3.3%
elysia main 138,480 0.67 ms 1.50 ms 60.5 MB
PR 142,101 0.66 ms 1.41 ms 60.1 MB +2.6%

With matched build flags the rewrite is at parity or slightly ahead on throughput, with marginally lower p50/p99 and RSS within noise. No regression.

As requested: published canary (LTO) vs local PR build (non-LTO)

Framework Binary req/s (best of 3) p50 p99 RSS Δ req/s
express canary 2e2230a81 47,769 1.92 ms 4.16 ms 89.3 MB
PR 76786b440 42,314 2.18 ms 4.66 ms 95.6 MB -11.4%
fastify canary 69,127 1.34 ms 2.89 ms 113.4 MB
PR 60,831 1.53 ms 3.27 ms 118.1 MB -12.0%
elysia canary 149,507 0.63 ms 1.36 ms 53.7 MB
PR 140,233 0.66 ms 1.49 ms 59.5 MB -6.2%

The 6-12% gap here lines up with the LTO vs non-LTO delta documented in scripts/build/profiles.ts (the btg profile comment). Once this PR has a linux-x64 CI artifact I can re-run against that for a true LTO-vs-LTO number.

Raw data (all 36 runs)

Same-toolchain (local release, non-LTO):

LABEL=main-express-r1 RPS=41369.34967077393 P50=0.002240064 P99=0.004653211 RSS_KB=95016 SUCCESS=1.0
LABEL=pr2-express-r1 RPS=41595.87266272149 P50=0.002206526 P99=0.004769115 RSS_KB=93712 SUCCESS=1.0
LABEL=main-express-r2 RPS=40558.2380264613 P50=0.002248189 P99=0.004840736 RSS_KB=97748 SUCCESS=1.0
LABEL=pr2-express-r2 RPS=40588.487870720666 P50=0.002218532 P99=0.004787946 RSS_KB=98228 SUCCESS=1.0
LABEL=main-express-r3 RPS=40164.99325194582 P50=0.002293524 P99=0.004891689 RSS_KB=93352 SUCCESS=1.0
LABEL=pr2-express-r3 RPS=41367.68204938798 P50=0.002215952 P99=0.004754929 RSS_KB=98820 SUCCESS=1.0
LABEL=main-fastify-r1 RPS=62619.23500251308 P50=0.001479851 P99=0.00321547 RSS_KB=121956 SUCCESS=1.0
LABEL=pr2-fastify-r1 RPS=64712.53706578089 P50=0.001439639 P99=0.00312319 RSS_KB=121516 SUCCESS=1.0
LABEL=main-fastify-r2 RPS=60741.39885998867 P50=0.001534144 P99=0.003306825 RSS_KB=120548 SUCCESS=1.0
LABEL=pr2-fastify-r2 RPS=63238.934082231615 P50=0.00146082 P99=0.003212499 RSS_KB=121804 SUCCESS=1.0
LABEL=main-fastify-r3 RPS=57989.158681876674 P50=0.001605662 P99=0.003391715 RSS_KB=119964 SUCCESS=1.0
LABEL=pr2-fastify-r3 RPS=55794.82431949291 P50=0.001649222 P99=0.003541728 RSS_KB=119828 SUCCESS=1.0
LABEL=main-elysia-r1 RPS=138170.75825080505 P50=0.000673225 P99=0.00148168 RSS_KB=61348 SUCCESS=1.0
LABEL=pr2-elysia-r1 RPS=141726.31520931728 P50=0.000661769 P99=0.001406469 RSS_KB=61920 SUCCESS=1.0
LABEL=main-elysia-r2 RPS=138479.84321339754 P50=0.000668068 P99=0.001496186 RSS_KB=61948 SUCCESS=1.0
LABEL=pr2-elysia-r2 RPS=139272.68822484228 P50=0.000659479 P99=0.001496964 RSS_KB=59524 SUCCESS=1.0
LABEL=main-elysia-r3 RPS=135120.06225991691 P50=0.000669057 P99=0.001626931 RSS_KB=62580 SUCCESS=1.0
LABEL=pr2-elysia-r3 RPS=142100.51216910593 P50=0.000659413 P99=0.001410317 RSS_KB=61576 SUCCESS=1.0

CI canary (LTO) vs local PR (non-LTO):

LABEL=canary-express-r1 RPS=47769.478677672785 P50=0.001924249 P99=0.004156298 RSS_KB=91468 SUCCESS=1.0
LABEL=pr-express-r1 RPS=42314.40891509191 P50=0.002183895 P99=0.004655112 RSS_KB=97860 SUCCESS=1.0
LABEL=canary-express-r2 RPS=46896.04703654922 P50=0.001955285 P99=0.004203238 RSS_KB=89096 SUCCESS=1.0
LABEL=pr-express-r2 RPS=35952.19977432369 P50=0.00250601 P99=0.005755512 RSS_KB=98060 SUCCESS=1.0
LABEL=canary-express-r3 RPS=43816.56441440306 P50=0.002062849 P99=0.004522195 RSS_KB=91944 SUCCESS=1.0
LABEL=pr-express-r3 RPS=40381.790012560625 P50=0.002268756 P99=0.004824348 RSS_KB=95704 SUCCESS=1.0
LABEL=canary-fastify-r1 RPS=67658.1510393544 P50=0.001371552 P99=0.00295735 RSS_KB=116208 SUCCESS=1.0
LABEL=pr-fastify-r1 RPS=59917.982527619446 P50=0.00154592 P99=0.003328061 RSS_KB=120548 SUCCESS=1.0
LABEL=canary-fastify-r2 RPS=66390.23170416798 P50=0.001384621 P99=0.003028206 RSS_KB=115768 SUCCESS=1.0
LABEL=pr-fastify-r2 RPS=60830.73210227568 P50=0.001525845 P99=0.00326506 RSS_KB=120980 SUCCESS=1.0
LABEL=canary-fastify-r3 RPS=69126.97604724011 P50=0.001344122 P99=0.00288599 RSS_KB=116132 SUCCESS=1.0
LABEL=pr-fastify-r3 RPS=55509.06511713213 P50=0.001651118 P99=0.00356525 RSS_KB=119540 SUCCESS=1.0
LABEL=canary-elysia-r1 RPS=149507.46952460633 P50=0.000625089 P99=0.001356977 RSS_KB=54940 SUCCESS=1.0
LABEL=pr-elysia-r1 RPS=137633.70679401132 P50=0.000667992 P99=0.001524142 RSS_KB=62760 SUCCESS=1.0
LABEL=canary-elysia-r2 RPS=146930.43791036378 P50=0.00062744 P99=0.001445462 RSS_KB=55240 SUCCESS=1.0
LABEL=pr-elysia-r2 RPS=137341.97083857734 P50=0.000653064 P99=0.001633563 RSS_KB=61788 SUCCESS=1.0
LABEL=canary-elysia-r3 RPS=146649.0477090695 P50=0.000635603 P99=0.001401454 RSS_KB=54712 SUCCESS=1.0
LABEL=pr-elysia-r3 RPS=140232.62799679633 P50=0.000659426 P99=0.001485341 RSS_KB=60896 SUCCESS=1.0

Server scripts:

// express.js
const app = require("express")();
app.get("/", (req, res) => res.send("Hello, World!"));
const server = app.listen(0, () => console.log("PORT=" + server.address().port));

// fastify.js
const fastify = require("fastify")({ logger: false });
fastify.get("/", async () => "Hello, World!");
fastify.listen({ port: 0, host: "127.0.0.1" }).then(() => console.log("PORT=" + fastify.server.address().port));

// elysia.ts
import { Elysia } from "elysia";
const app = new Elysia().get("/", () => "Hello, World!").listen(0);
console.log("PORT=" + app.server!.port);

oha --no-tui -z 15s -c 100 --output-format json http://127.0.0.1:$PORT/

Comment thread Cargo.toml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/io/windows_event_loop.rs (1)

300-309: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Export Result from bun_io or switch this init() to crate::error::Result<Self>. src/io/error.rs defines pub type Result<T, E = Error>, but src/io/lib.rs only re-exports Error, so crate::Result at this call site has no crate-root definition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/io/windows_event_loop.rs` around lines 300 - 309, Update Waker::init to
use the existing crate::error::Result<Self> alias, or re-export the io Result
alias from bun_io before using crate::Result. Preserve the current infallible
initialization behavior and Result<Waker, crate::Error> API contract.
src/io/posix_event_loop.rs (1)

857-871: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Clear Flags::OneShot in the NeedsRearm skip path. register_with_fd_impl() never clears that bit for one_shot: false, so a later persistent re-register can still be handled as one-shot and get disarmed on the next event.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/io/posix_event_loop.rs` around lines 857 - 871, Update the NeedsRearm
early-return path in unregister around register_with_fd_impl behavior to also
remove Flags::OneShot before returning. Preserve the existing cleanup of the
other polling flags and the skip behavior for non-forced unregisters.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/http/lib.rs`:
- Around line 1284-1289: Retain validate_request_target’s rejection of spaces,
control bytes, and DEL, and ensure it is applied to href/path/host values before
constructing request or CONNECT lines, including proxy paths. Preserve the
existing InvalidURL error behavior.

In `@src/io/lib.rs`:
- Around line 15-16: Update the exports in src/io/lib.rs alongside Error so the
Result type used by the crate::Result<Self> call site is available from the
crate root; re-export the existing error::Result rather than introducing a new
result type.

In `@src/jsc/event_loop.rs`:
- Around line 1127-1128: Remove the duplicate consecutive process_gc_timer call
in tick_possibly_forever, leaving a single invocation in the event-loop
processing sequence.

In `@src/jsc/ipc.rs`:
- Around line 758-760: Update owner_teardown and the related close paths around
the socket teardown logic so they do not call close_socket while holding
JsCell::with_mut through with_queue. Reuse the existing audited reentrant queue
projection helper consistently, allowing on_close to re-project the same queue
without violating the borrow scope.
- Around line 670-684: Condense the lifecycle comments around IpcData and the
additionally referenced sections near owner teardown and related callbacks to no
more than three lines each. Preserve only the essential ownership/refcount and
teardown invariant, removing extended protocol, path, and implementation
explanations while leaving code unchanged.

---

Outside diff comments:
In `@src/io/posix_event_loop.rs`:
- Around line 857-871: Update the NeedsRearm early-return path in unregister
around register_with_fd_impl behavior to also remove Flags::OneShot before
returning. Preserve the existing cleanup of the other polling flags and the skip
behavior for non-forced unregisters.

In `@src/io/windows_event_loop.rs`:
- Around line 300-309: Update Waker::init to use the existing
crate::error::Result<Self> alias, or re-export the io Result alias from bun_io
before using crate::Result. Preserve the current infallible initialization
behavior and Result<Waker, crate::Error> API contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 343983e5-c8f9-43ed-a2e5-8d44f9937cc5

📥 Commits

Reviewing files that changed from the base of the PR and between f2c43af and 39e9610.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (37)
  • scripts/build/bun.ts
  • scripts/build/source.ts
  • src/http/Cargo.toml
  • src/http/HTTPContext.rs
  • src/http/HTTPThread.rs
  • src/http/ProxyTunnel.rs
  • src/http/error.rs
  • src/http/h2_client/ClientSession.rs
  • src/http/h3_client/ClientContext.rs
  • src/http/h3_client/ClientSession.rs
  • src/http/h3_client/PendingConnect.rs
  • src/http/h3_client/callbacks.rs
  • src/http/h3_client/encode.rs
  • src/http/lib.rs
  • src/http/ssl_config.rs
  • src/http_jsc/websocket_client.rs
  • src/http_jsc/websocket_client/WebSocketProxyTunnel.rs
  • src/http_jsc/websocket_client/WebSocketUpgradeClient.rs
  • src/install/Cargo.toml
  • src/install/PackageManager/security_scanner.rs
  • src/install/lifecycle_script_runner.rs
  • src/install/resolution.rs
  • src/io/Cargo.toml
  • src/io/PipeReader.rs
  • src/io/PipeWriter.rs
  • src/io/lib.rs
  • src/io/posix_event_loop.rs
  • src/io/windows_event_loop.rs
  • src/jsc/Cargo.toml
  • src/jsc/Debugger.rs
  • src/jsc/VirtualMachine.rs
  • src/jsc/error.rs
  • src/jsc/event_loop.rs
  • src/jsc/ipc.rs
  • src/jsc/lib.rs
  • src/jsc/rare_data.rs
  • src/jsc/web_worker.rs
💤 Files with no reviewable changes (1)
  • src/install/resolution.rs

@robobun

robobun commented Jul 12, 2026

Copy link
Copy Markdown
Collaborator

Ceiling benchmark (LTO vs LTO)

Binaries: published canary 2e2230a81 (CI LTO, from GitHub releases) vs PR 29b312126 built locally with --profile=btg (LTO, mirrors CI release codegen per scripts/build/profiles.ts; the Buildkite artifact download redirects to s3.amazonaws.com which this container's egress proxy blocks with 403, so I couldn't use the actual CI artifact). Binary sizes within 0.1% of each other (76.97 MB vs 77.02 MB).

Setup: oha 1.15.0, -z 15s, keepalive on (oha default), 3s warmup, 3 runs per combo (best shown), interleaved canary/PR. Linux x64, Xeon Platinum 8375C, 16 vCPU.

Workload c Binary req/s (best of 3) p50 p99 RSS Δ req/s
hello 100 canary 154,302 0.602 ms 1.33 ms 32.5 MB
PR 155,706 0.602 ms 1.30 ms 39.7 MB +0.9%
hello 512 canary 154,024 3.189 ms 6.33 ms 33.8 MB
PR 157,394 3.106 ms 6.17 ms 40.9 MB +2.2%
/static 100 canary 194,754 0.489 ms 1.02 ms 26.1 MB
PR 191,375 0.487 ms 1.09 ms 33.1 MB -1.7%
/static 512 canary 197,302 2.444 ms 4.84 ms 25.8 MB
PR 195,877 2.446 ms 5.01 ms 33.1 MB -0.7%
/dynamic 100 canary 143,597 0.628 ms 1.54 ms 35.8 MB
PR 133,387 0.656 ms 1.79 ms 43.3 MB -7.1%*
/dynamic 512 canary 137,948 3.519 ms 6.99 ms 36.8 MB
PR 128,532 3.653 ms 7.23 ms 42.5 MB -6.8%*

Notes:

  • hello and /static are tight: PR within ±2% of canary at both connection levels, with equal or better p50/p99 on hello. The /static path (pre-built Response object) ceilings ~27% higher than hello on both binaries.
  • /dynamic was too noisy on this box to isolate a signal: individual runs swung from 44k to 143k req/s at c=100 on both binaries in interleaved order (see raw data). A second full pass of /dynamic flipped the sign at c=100 (PR +12.9%). Table shows the best from across both passes per combo. I wouldn't read the -7% as real without a quieter box.
  • RSS: PR sits a consistent ~7 MB higher across every workload. This lines up with the slab's initial chunk reservation (a 64 KiB mmap per size class doesn't account for it alone; more likely the combination of slab chunks + the per-loop poll registry + the 512 KiB loop recv buffer now owned by Rust instead of shared with the C heap arena).
Raw data (all 48 runs)
canary: 1.4.0-canary.1+2e2230a81
pr:     1.4.0-canary.1+29b312126
oha:    oha 1.15.0
cpu:    16 cores, Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz

LABEL=canary-hello-c100-r1 RPS=154302.18584957148 P50=0.000602409 P99=0.001332175 RSS_KB=33260 SUCCESS=1.0
LABEL=pr-hello-c100-r1 RPS=150413.38787884594 P50=0.000611264 P99=0.001417931 RSS_KB=41756 SUCCESS=1.0
LABEL=canary-hello-c100-r2 RPS=153749.46136937098 P50=0.000604434 P99=0.001327876 RSS_KB=34280 SUCCESS=1.0
LABEL=pr-hello-c100-r2 RPS=155705.71348738033 P50=0.000601943 P99=0.001297973 RSS_KB=40688 SUCCESS=1.0
LABEL=canary-hello-c100-r3 RPS=154231.47938084722 P50=0.000604236 P99=0.001338779 RSS_KB=33656 SUCCESS=1.0
LABEL=pr-hello-c100-r3 RPS=154884.85681708154 P50=0.000603218 P99=0.001284412 RSS_KB=40856 SUCCESS=1.0
LABEL=canary-hello-c512-r1 RPS=149362.51918592758 P50=0.003301441 P99=0.006556822 RSS_KB=34620 SUCCESS=1.0
LABEL=pr-hello-c512-r1 RPS=148350.16103096752 P50=0.003334956 P99=0.006703305 RSS_KB=41224 SUCCESS=1.0
LABEL=canary-hello-c512-r2 RPS=154023.97059277815 P50=0.003189193 P99=0.006334612 RSS_KB=34576 SUCCESS=1.0
LABEL=pr-hello-c512-r2 RPS=152855.7737099207 P50=0.003194623 P99=0.006253138 RSS_KB=42076 SUCCESS=1.0
LABEL=canary-hello-c512-r3 RPS=153653.91770599695 P50=0.003181067 P99=0.006423363 RSS_KB=34432 SUCCESS=1.0
LABEL=pr-hello-c512-r3 RPS=157394.44158281747 P50=0.00310588 P99=0.006171492 RSS_KB=41864 SUCCESS=1.0
LABEL=canary-static-c100-r1 RPS=194754.04395348488 P50=0.000488642 P99=0.001017378 RSS_KB=26712 SUCCESS=1.0
LABEL=pr-static-c100-r1 RPS=191375.1474027325 P50=0.000487202 P99=0.001092656 RSS_KB=33880 SUCCESS=1.0
LABEL=canary-static-c100-r2 RPS=191674.3048357868 P50=0.000492768 P99=0.001050245 RSS_KB=26716 SUCCESS=1.0
LABEL=pr-static-c100-r2 RPS=186528.32719167153 P50=0.000495764 P99=0.001123515 RSS_KB=33852 SUCCESS=1.0
LABEL=canary-static-c100-r3 RPS=194392.28907168866 P50=0.000488705 P99=0.001021242 RSS_KB=26784 SUCCESS=1.0
LABEL=pr-static-c100-r3 RPS=189364.14989661408 P50=0.000493314 P99=0.001083268 RSS_KB=33904 SUCCESS=1.0
LABEL=canary-static-c512-r1 RPS=190827.36620665988 P50=0.002532081 P99=0.005262921 RSS_KB=26572 SUCCESS=1.0
LABEL=pr-static-c512-r1 RPS=190489.91169149894 P50=0.00250531 P99=0.005136719 RSS_KB=33808 SUCCESS=1.0
LABEL=canary-static-c512-r2 RPS=190484.432502533 P50=0.002561879 P99=0.005271491 RSS_KB=26548 SUCCESS=1.0
LABEL=pr-static-c512-r2 RPS=195877.47615780853 P50=0.002446485 P99=0.005011162 RSS_KB=33908 SUCCESS=1.0
LABEL=canary-static-c512-r3 RPS=197302.45130156958 P50=0.002443615 P99=0.004839715 RSS_KB=26468 SUCCESS=1.0
LABEL=pr-static-c512-r3 RPS=179862.03190796488 P50=0.002679034 P99=0.005679851 RSS_KB=33816 SUCCESS=1.0

--- /dynamic first pass ---
LABEL=canary-dynamic-c100-r1 RPS=143597.04370232866 P50=0.000627995 P99=0.00154042 RSS_KB=36612 SUCCESS=1.0
LABEL=pr-dynamic-c100-r1 RPS=133387.27334741218 P50=0.00065635 P99=0.00179239 RSS_KB=44320 SUCCESS=1.0
LABEL=canary-dynamic-c100-r2 RPS=88249.35317239624 P50=0.001137475 P99=0.00223302 RSS_KB=37448 SUCCESS=1.0
LABEL=pr-dynamic-c100-r2 RPS=95546.43747064425 P50=0.001090262 P99=0.002107317 RSS_KB=44080 SUCCESS=1.0
LABEL=canary-dynamic-c100-r3 RPS=91121.83392580325 P50=0.001115465 P99=0.002141946 RSS_KB=36776 SUCCESS=1.0
LABEL=pr-dynamic-c100-r3 RPS=85908.94096892084 P50=0.001152011 P99=0.002286248 RSS_KB=43660 SUCCESS=1.0
LABEL=canary-dynamic-c512-r1 RPS=78068.89487451341 P50=0.006663097 P99=0.008046668 RSS_KB=37844 SUCCESS=1.0
LABEL=pr-dynamic-c512-r1 RPS=68495.50063419557 P50=0.007427569 P99=0.008994618 RSS_KB=42540 SUCCESS=1.0
LABEL=canary-dynamic-c512-r2 RPS=69955.07960680724 P50=0.007226149 P99=0.008758785 RSS_KB=36608 SUCCESS=1.0
LABEL=pr-dynamic-c512-r2 RPS=61479.78790391741 P50=0.008060202 P99=0.012753216 RSS_KB=53064 SUCCESS=1.0
LABEL=canary-dynamic-c512-r3 RPS=45160.42828244029 P50=0.010765895 P99=0.021342114 RSS_KB=46772 SUCCESS=1.0
LABEL=pr-dynamic-c512-r3 RPS=44626.02504933788 P50=0.010731382 P99=0.022297596 RSS_KB=53912 SUCCESS=1.0

--- /dynamic second pass ---
LABEL=canary-dynamic-c100-r1 RPS=44520.8517213154 P50=0.001941158 P99=0.005625141 RSS_KB=45512 SUCCESS=1.0
LABEL=pr-dynamic-c100-r1 RPS=47404.68070851458 P50=0.001827368 P99=0.005373329 RSS_KB=51044 SUCCESS=1.0
LABEL=canary-dynamic-c100-r2 RPS=49356.04687387592 P50=0.001740516 P99=0.005374882 RSS_KB=46592 SUCCESS=1.0
LABEL=pr-dynamic-c100-r2 RPS=52739.14082504637 P50=0.001674727 P99=0.004834956 RSS_KB=53920 SUCCESS=1.0
LABEL=canary-dynamic-c100-r3 RPS=106457.10364856425 P50=0.00079351 P99=0.002288176 RSS_KB=37332 SUCCESS=1.0
LABEL=pr-dynamic-c100-r3 RPS=120209.29760806846 P50=0.000675607 P99=0.001992744 RSS_KB=45036 SUCCESS=1.0
LABEL=canary-dynamic-c512-r1 RPS=137948.14061806301 P50=0.003519343 P99=0.006985058 RSS_KB=37716 SUCCESS=1.0
LABEL=pr-dynamic-c512-r1 RPS=125417.39957275457 P50=0.003660061 P99=0.008231071 RSS_KB=43124 SUCCESS=1.0
LABEL=canary-dynamic-c512-r2 RPS=129524.42009422753 P50=0.003706854 P99=0.007340004 RSS_KB=36852 SUCCESS=1.0
LABEL=pr-dynamic-c512-r2 RPS=128531.81870728599 P50=0.003652893 P99=0.007229949 RSS_KB=43528 SUCCESS=1.0
LABEL=canary-dynamic-c512-r3 RPS=106598.51580610257 P50=0.004257954 P99=0.007524086 RSS_KB=37472 SUCCESS=1.0
LABEL=pr-dynamic-c512-r3 RPS=117597.07508409223 P50=0.003786694 P99=0.007566847 RSS_KB=44428 SUCCESS=1.0

Server scripts:

// hello.js
const server = Bun.serve({ port: 0, fetch() { return new Response("hello"); } });
console.log("PORT=" + server.port);

// routes.js  (note: (globalThis.i ??= 0)++ is a syntax error; rewritten)
globalThis.i = 0;
const server = Bun.serve({
  port: 0,
  routes: {
    "/static": new Response("hello"),
    "/dynamic": () => new Response("hii" + globalThis.i++),
  },
});
console.log("PORT=" + server.port);

oha --no-tui -z 15s -c {100|512} --output-format json http://127.0.0.1:$PORT{/|/static|/dynamic}

Jarred-Sumner and others added 2 commits July 12, 2026 22:55
…tener-close deref, review findings

- send_sync no longer ManuallyDrop-leaks response metadata (LSan exit-134 on
  bun info/audit under the asan lane); SyncHTTPResponse owns the metadata and
  exposes it through a lifetime-tied accessor so header slices cannot outlive
  the backing buffer
- the intentionally-crashing native-plugin fixture disables crash reporting
  so its late-arriving SIGSEGV report can no longer be attributed to whatever
  test runs next (the fetch.stream / net-write-slow 'crashes')
- http-chunked-server fixture: listen() before printing the port (RST window
  caused spurious ConnectionRefused)
- SNI select_cert fallthrough re-reads the listener backref after user JS
  (sync resolver closing the listener hit a nulled ext)
- connecting-socket unlink keeps links intact (C parity for re-entrant
  close_all walks); SNI label collection is allocation-free again; stale
  feature-gate comment
Comment thread Cargo.toml
"src/shell_parser",
"src/tcc_sys",
"src/uws_sys",
"src/usockets",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 🟡 Three more stale references to files this PR deletes, in files the earlier grep-and-update passes missed because two of them are outside the diff: src/platform/linux.rs:13-14 ("The C caller in epoll_kqueue.c decodes errno from the return value" — epoll_kqueue.c is deleted; the caller is now src/usockets/unsafe_core/poll_access.rs), src/js/internal-for-testing.ts:280 ("The syscalls instrumented in bsd.c" — bsd.c is deleted; fault injection is now src/usockets/fault.rs), and src/usockets/kind.rs:2 ("identical to src/uws_sys/SocketKind.rs" — that file is deleted here). Same class as the already-fixed lib.rs/cabi.rs/README.md rounds; no runtime effect. (Filed against Cargo.toml because platform/linux.rs and internal-for-testing.ts have no diff line ranges.)

Extended reasoning...

What the issue is

Three doc comments describe a live relationship with files this PR deletes:

  1. src/platform/linux.rs:13-14 — the doc comment on raw_syscall6 (which backs sys_epoll_pwait2) reads: "The C caller in epoll_kqueue.c decodes errno from the return value (ret == -EINTR, ret != -ENOSYS), so the in-band encoding is what it expects." This PR deletes packages/bun-usockets/src/eventing/epoll_kqueue.c; the sole remaining caller is src/usockets/unsafe_core/poll_access.rs. The comment describes a caller contract for a caller that no longer exists.

  2. src/js/internal-for-testing.ts:280 — the JSDoc on SocketFaultSyscall reads: "The syscalls instrumented in bsd.c". This PR deletes packages/bun-usockets/src/bsd.c and fault_inject.c; fault injection now lives in src/usockets/fault.rs.

  3. src/usockets/kind.rs:2 — reads: "Discriminants FROZEN — identical to src/uws_sys/SocketKind.rs". ls src/uws_sys/ shows only _libusockets.h, libuwsockets.cpp, libuwsockets_h3.cppSocketKind.rs is deleted by this same PR.

Why the earlier passes missed them

This is the same finding class as the previously-accepted-and-fixed nits on this PR: #4 (lib.rs:12-14 + cabi.rs:12-16 → SocketKind.rs / "live C"), #8 (README.md → epoll_kqueue.c), and #13 (lib.rs:40 → "feature-gated OFF"). Those fix passes covered files the PR touches. The first two files here — src/platform/linux.rs and src/js/internal-for-testing.ts — are not in the PR's changed-files list, so a grep-and-update sweep over the diff would not find them. The third (kind.rs) is a new file added by this PR whose module doc references a file deleted in the same PR.

Impact

No runtime effect — pure doc staleness, hence nit. The platform/linux.rs one is the most misleading of the three: it documents an errno-in-band caller contract ("the C caller decodes errno from the return value") for a caller that no longer exists, so a reader trying to understand why the function returns raw -errno instead of setting thread-local errno would look for epoll_kqueue.c and find nothing. Per CLAUDE.md "Comments carry only durable non-obvious content" and "grep the whole repo including cfg-gated code" when a change invalidates surrounding docs.

Step-by-step proof

  1. sed -n '13,14p' src/platform/linux.rs"The C caller in epoll_kqueue.c decodes errno from the return value (ret == -EINTR, ret != -ENOSYS)".
  2. ls packages/bun-usockets/src/eventing/ → No such file or directory. This PR deletes epoll_kqueue.c.
  3. rg sys_epoll_pwait2 src/usockets/unsafe_core/poll_access.rs — the new (and only) caller.
  4. sed -n '280p' src/js/internal-for-testing.ts"The syscalls instrumented in bsd.c".
  5. ls packages/bun-usockets/src/bsd.c → No such file or directory. This PR deletes it; fault injection is now src/usockets/fault.rs.
  6. sed -n '2p' src/usockets/kind.rs"identical to src/uws_sys/SocketKind.rs".
  7. ls src/uws_sys/_libusockets.h libuwsockets.cpp libuwsockets_h3.cpp. No SocketKind.rs — deleted by this PR.
  8. Neither src/platform/linux.rs nor src/js/internal-for-testing.ts appears in this PR's changed-files list — hence why the earlier fix passes over touched files missed them.

How to fix

  • linux.rs:13-14: replace "The C caller in epoll_kqueue.c" with "The caller in src/usockets/unsafe_core/poll_access.rs" (or just "The caller"), keeping the errno-in-band contract description.
  • internal-for-testing.ts:280: replace "instrumented in bsd.c" with "instrumented in src/usockets/fault.rs".
  • kind.rs:2: drop "identical to src/uws_sys/SocketKind.rs" — the docs/cabi.md §3.8 reference on the same line already covers the freeze contract, and SocketKind.rs no longer exists to be identical to.

(Filed against Cargo.toml because platform/linux.rs and internal-for-testing.ts have no diff line ranges in this PR.)

Comment on lines +554 to +555
// bun_uws_shim::ResponseKind, not the shim's: consumed only by unmigrated
// bun_uws-typed FFI (`FetchHeaders::to_uws_response`, `CookieMap::write`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Companion to unresolved comment #16 (which covers deleted C-filename references): ~10 more comments still reference the deleted bun_uws / bun_uws_sys Rust crates or src/uws_sys/SocketKind.rs, which a C-filename grep pass would not find. Two are outright self-contradictory after a mechanical rename (bun_uws_shim::ResponseKind, not the shim's — bun_uws_shim IS the shim); three are in packages/bun-uws/*.h, a directory the earlier src/-scoped grep passes don't reach. All comment-only, no runtime effect. One rg 'bun_uws\b|bun_uws_sys|uws_sys/SocketKind' pass over comments would catch them — full site list in the details.

Extended reasoning...

What the issue is

This PR deletes the bun_uws and bun_uws_sys crates (removed from Cargo.toml members and workspace.dependencies) and src/uws_sys/SocketKind.rs (only _libusockets.h / libuwsockets.cpp / libuwsockets_h3.cpp survive in src/uws_sys/), but ~10 comments still reference them. The still-open comment #16 covers references to the deleted C filenames (epoll_kqueue.c, bsd.c, SocketKind.rs in kind.rs:2); this is the companion set — references to the deleted Rust crate names — which a C-filename grep would not find:

(a) Self-contradictory after a mechanical bun_uws:: → bun_uws_shim:: rename (both are + lines added by this PR):

  • src/runtime/server/RequestContext.rs:554-555: "bun_uws_shim::ResponseKind, not the shim's: consumed only by unmigrated bun_uws-typed FFI" — but bun_uws_shim IS the shim, so "not the shim's" is meaningless. Evidently written as "bun_uws::ResponseKind, not the shim's" during the intermediate two-crate state, then hit by a find-replace pass.
  • src/runtime/server/server_body.rs:37-38: "ResponseKind stays bun_uws-typed" immediately above use bun_uws_shim::ResponseKind;.

(b) Development-phase / re-export-chain comments in NEW uws_shim files referencing the deleted crates:

  • src/uws_shim/us_socket.rs:88-89: "Also #[no_mangle]-defined in src/uws_sys until D1 deletes that crate; the two crates must never both link" — D1 already happened (same pattern as the fixed cabi.rs:12-16 finding).
  • src/uws_shim/Response.rs:25-27: "Higher tiers (bun_uws, bun_runtime) re-export this as pub use bun_uws_sys::SocketAddress" — both crates deleted; no such re-export chain.
  • src/uws_shim/Response.rs:63/65/67: three doc comments say "concrete type lives in bun_uws" — deleted; these are opaque handles for the C++ uWS layer.
  • src/sourcemap/Mapping.rs:107: "Mirrors any_dispatch! at src/uws_sys/Response.rs:581" — file deleted; the macro now lives in src/uws_shim/Response.rs.

(c) Surviving C++ headers pointing at src/uws_sys/SocketKind.rs (deleted; the BUN_SOCKET_KIND_* #[no_mangle] statics now live in src/usockets/cabi.rs):

  • packages/bun-uws/src/SocketKinds.h:2: "src/uws_sys/SocketKind.rs is the source of truth for these ordinals"
  • packages/bun-uws/src/HttpContext.h:128 and WebSocketContext.h:53: "the ordinals are linked from src/uws_sys/SocketKind.rs"

Why the earlier passes missed them

Rounds #4/#8/#13 and the still-open #16 covered stale references at lib.rs/cabi.rs/README.md/platform/linux.rs/internal-for-testing.ts/kind.rs — found by grepping for the deleted C filenames and by touching files inside src/. Group (a)/(b) reference the deleted Rust crate names instead. Group (c) is under packages/bun-uws/, which the src/-scoped sweeps don't reach — even though HttpContext.h is in this PR's changed-files list (the author was already editing it).

Impact

No runtime effect — pure comment staleness, hence nit. The two group-(a) comments are actively misleading (self-contradictory nonsense), the group-(b) "D1" / re-export-chain comments describe a development phase that no longer exists, and the group-(c) headers point future readers at the wrong file for the ABI ordinal source of truth. Per CLAUDE.md "Comments carry only durable non-obvious content" and "Delete dead code in the same PR that makes it dead".

Step-by-step proof

  1. Cargo.toml diff removes "src/uws" from members and bun_uws = { path = "src/uws" } from workspace.dependencies; adds bun_uws_shim. So bun_uws is deleted and bun_uws_shim IS the shim crate.
  2. RequestContext.rs:554 (+ line): "bun_uws_shim::ResponseKind, not the shim's" — literally self-contradictory given (1). server_body.rs:37-39: comment says "stays bun_uws-typed", import right below is bun_uws_shim::ResponseKind.
  3. ls src/uws_sys/_libusockets.h libuwsockets.cpp libuwsockets_h3.cpp. No .rs files. So us_socket.rs:88-89 ("until D1 deletes that crate"), Response.rs:25-27 ("pub use bun_uws_sys::SocketAddress"), Response.rs:63/65/67 ("lives in bun_uws"), and Mapping.rs:107 ("src/uws_sys/Response.rs:581") all reference deleted files/crates.
  4. rg 'uws_sys/SocketKind' packages/bun-uws/src → three hits at exactly SocketKinds.h:2, HttpContext.h:128, WebSocketContext.h:53. rg 'BUN_SOCKET_KIND_' src/usockets/cabi.rs → the #[no_mangle] statics live there now.
  5. None of these locations overlap the still-open Fix browser map #16 (platform/linux.rs, internal-for-testing.ts, kind.rs:2) or the previously-fixed rounds — distinct sites, same class.

How to fix

One rg 'bun_uws\b|bun_uws_sys|uws_sys/SocketKind' pass over comments:

  • (a): delete both comments outright — after the migration there is only one ResponseKind, so the distinction they try to draw doesn't exist.
  • (b): delete us_socket.rs:88-89 and Response.rs:25-27; change Response.rs:63/65/67 to reference the C++ uWS layer; repoint Mapping.rs:107 at src/uws_shim/Response.rs (or drop the cross-reference).
  • (c): point all three headers at src/usockets/cabi.rs (where the BUN_SOCKET_KIND_* #[no_mangle] exports live) or src/usockets/kind.rs (the enum definition).

(Filed at RequestContext.rs:554 — the one site that has a commentable diff line range; the new uws_shim/*.rs files and the packages/bun-uws/*.h lines have none.)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/usockets/tls/sni.rs`:
- Around line 151-161: Update the SNI pattern insertion method containing
collect_labels and remove_rec so it returns immediately when collect_labels
rejects a pattern, before any trie mutation or SslCtx reference retention
occurs. Ensure over-limit patterns are not stored, while valid patterns continue
through the existing add flow.
- Around line 159-161: Update the lookup in find_ctx to use the exact-match
traversal rather than get(), so querying a concrete hostname does not resolve
wildcard children. Preserve the existing label collection and return the exact
context when the full pattern exists, otherwise return null.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 15ee566c-9713-4758-89fa-c5e06311252d

📥 Commits

Reviewing files that changed from the base of the PR and between f3dcf31 and 93d9e15.

📒 Files selected for processing (15)
  • scripts/rust-miri.ts
  • src/http/AsyncHTTP.rs
  • src/install/npm.rs
  • src/runtime/cli/audit_command.rs
  • src/runtime/cli/create_command.rs
  • src/runtime/cli/pm_view_command.rs
  • src/runtime/cli/publish_command.rs
  • src/runtime/cli/upgrade_command.rs
  • src/standalone_graph/StandaloneModuleGraph.rs
  • src/usockets/group.rs
  • src/usockets/lib.rs
  • src/usockets/tls/sni.rs
  • src/usockets/unsafe_core/ffi.rs
  • test/bundler/native-plugin.test.ts
  • test/js/web/fetch/http-chunked-server.c

Comment thread src/usockets/tls/sni.rs
Comment on lines +151 to +161
let mut buf: [&[u8]; MAX_LABELS] = [b""; MAX_LABELS];
let Some(n) = collect_labels(pattern.to_bytes(), &mut buf) else {
return;
};
drop(remove_rec(&mut self.root, &buf[..n]));
}

fn lookup(&self, hostname: &CStr) -> Option<&Entry> {
let mut buf: [&[u8]; MAX_LABELS] = [b""; MAX_LABELS];
let n = collect_labels(hostname.to_bytes(), &mut buf)?;
get(&self.root, &buf[..n])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject over-limit SNI patterns before storing them.

collect_labels() rejects patterns with more than MAX_LABELS labels, but add() still accepts and stores them. Such entries become unreachable to lookup and removal, while their SslCtx up-reference remains held. Apply the same limit before mutating the trie.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/usockets/tls/sni.rs` around lines 151 - 161, Update the SNI pattern
insertion method containing collect_labels and remove_rec so it returns
immediately when collect_labels rejects a pattern, before any trie mutation or
SslCtx reference retention occurs. Ensure over-limit patterns are not stored,
while valid patterns continue through the existing add flow.

Comment thread src/usockets/tls/sni.rs
Comment on lines +159 to +161
let mut buf: [&[u8]; MAX_LABELS] = [b""; MAX_LABELS];
let n = collect_labels(hostname.to_bytes(), &mut buf)?;
get(&self.root, &buf[..n])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep exact find_ctx lookups separate from wildcard resolution.

The lookup path uses get(), which falls back to * children, but find_ctx() is documented as exact-pattern lookup. If only *.example.com exists, querying api.example.com returns the wildcard context instead of null.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/usockets/tls/sni.rs` around lines 159 - 161, Update the lookup in
find_ctx to use the exact-match traversal rather than get(), so querying a
concrete hostname does not resolve wildcard children. Preserve the existing
label collection and return the exact context when the full pattern exists,
otherwise return null.

Core: clamp expired tick timespecs to immediate-return (spawnSync could park
forever past its deadline); close_all walks restart from the head after every
dispatch instead of trusting cached next pointers (re-entrant adopt/close
could route the walk into a foreign group or exit early, leaving parked
sockets with dangling group pointers); nested-tick depth bracketing keeps
slots undrained across close_all frames; kqueue poll_stop deletes an armed
one-shot WRITE knote on every fd-outlives-poll path; happy-eyeballs attempt
sockets close through the connecting cancel path; poll-registry fds are
range-checked against the 27-bit poll field; field-granular raw-place access
replaces whole-struct &mut Loop on paths foreign threads touch concurrently.

node:net: partial-writev remainder used swapped operands, duplicating or
dropping bytes under backpressure (inherited from the pre-rewrite
implementation; regression test fails on released bun); fully-written
buffered prefixes are now cleared; bytes_written accounting added; detached
handles are no longer resurrected by late TLS events; upgradeTLS twins are
retired on reconnect/close/deinit paths.

IPC: NODE_HANDLE retransmission counter resets on ack; partial sendmsg
retries no longer resend the SCM_RIGHTS fd; oversized JSON-mode messages
error instead of panicking; nested on_end uses the raw-place projection.

HTTP thread: exit-path context drops deferred until the loop parks; queued
writes for pending h2 attaches are held, not discarded.
Comment thread Cargo.toml
"src/shell_parser",
"src/tcc_sys",
"src/uws_sys",
"src/usockets",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 The doc comments at src/usockets/tls/sni.rs:164 ("Exact-pattern lookup") and src/usockets/unsafe_core/ffi.rs:714 ("exact-pattern SNI lookup") are wrong — find_ctx()lookup()get() falls back to * children (sni.rs:107), which is wildcard-aware and matches the deleted C (sni_findgetUser). The unresolved CodeRabbit comment at sni.rs:161 suggests the opposite fix (change the impl to exact-match), but that would regress App.h onMissingServerName — which passes the concrete negotiated hostname after user JS may have registered *.example.com, and needs the wildcard match. Fix the two doc comments; do not apply the CodeRabbit suggestion. (Filed against Cargo.toml because the new sni.rs file has no commentable diff line ranges.)

Extended reasoning...

What the issue is

Two doc comments describe find_ctx() as an exact-pattern lookup, but the implementation is (correctly) wildcard-aware:

  • src/usockets/tls/sni.rs:164: /// Exact-pattern lookup; returns an OWNED reference (caller unrefs)
  • src/usockets/unsafe_core/ffi.rs:714: /// `us_listen_socket_find_server_name_ctx`: exact-pattern SNI lookup

But find_ctx() (sni.rs:166) calls self.lookup() (sni.rs:158), which calls get() (sni.rs:98–108), and get() falls back to the * child at sni.rs:107 (get(node.children.get(&b"*"[..])?, rest)) — the same wildcard-aware traversal that resolve() (sni.rs:184, correctly documented as "Wildcard-aware") uses. So the two doc comments contradict the implementation.

Why the implementation is correct (C-parity)

The deleted C function this ports is us_listen_socket_find_server_name_ctx (openssl.c:2506–2513), which called sni_find. From the deleted sni_tree.cpp in this PR's diff, sni_find called getUser(root, 0, labels, numLabels), and getUser (sni_tree.cpp:92–116) has explicit wildcard fallback:

/* Try and match by wildcard */
it = root->children.find("*");
if (it == root->children.end()) {
    return nullptr;
}
return getUser(it->second.get(), label + 1, labels, numLabels);

So the Rust impl exactly matches the deleted C — the doc comments are what's wrong.

Why the CodeRabbit suggestion should NOT be applied

There is an unresolved CodeRabbit inline comment at sni.rs:161 (dated 2026-07-12T23:45:03Z) suggesting the opposite fix: "Update the lookup in find_ctx to use the exact-match traversal rather than get(), so querying a concrete hostname does not resolve wildcard children."

Applying that would be a regression. The sole caller of us_listen_socket_find_server_name_ctx is App.h:325 inside onMissingServerName:

static struct ssl_ctx_st *onMissingServerName(..., const char *hostname, ...) {
    ...
    /* The handler is expected to have registered the name via addServerName();
     * hand the newly-registered context back so the in-flight handshake uses it */
    return us_listen_socket_find_server_name_ctx(ls, hostname);
}

Here hostname is the concrete negotiated servername from the ClientHello (e.g. foo.example.com). The user's missingServerName handler may have just called addServerName("*.example.com", ...). With wildcard matching (current behavior, C-parity), find_server_name_ctx(ls, "foo.example.com") returns the newly-registered *.example.com context and the in-flight handshake uses it. With CodeRabbit's exact-match fix, it would return null and the handshake would fall back to the default context — breaking the wildcard-registration flow that the C supported.

Impact

No runtime effect — the implementation is correct today; only the two doc comments are wrong. Hence nit. But the finding's real value is flagging that the still-open CodeRabbit suggestion is backwards: applying it (which the "🤖 Prompt for AI Agents" block invites) would silently regress a user-visible flow that the deleted C supported and that has no test coverage in this PR.

Step-by-step proof

  1. sni.rs:164: doc says "Exact-pattern lookup".
  2. sni.rs:166–167: find_ctx() calls self.lookup(pattern).
  3. sni.rs:158–162: lookup() calls get(&self.root, &buf[..n]).
  4. sni.rs:107: get() falls back to node.children.get(&b"*"[..])wildcard-aware, not exact.
  5. sni.rs:181–185: resolve() uses the SAME lookup() and is correctly documented "Wildcard-aware".
  6. Deleted sni_tree.cpp in the diff: sni_findgetUser, which does root->children.find("*") fallback — the C was wildcard-aware.
  7. App.h:313–325: onMissingServerName calls us_listen_socket_find_server_name_ctx(ls, hostname) with the concrete negotiated hostname; the comment at 320–323 says the handler registered a name via addServerName() — which accepts wildcard patterns. Wildcard matching is required for a *.example.com registration to satisfy a foo.example.com request.
  8. Therefore: implementation is C-parity correct; the two doc comments are misleading; the CodeRabbit suggestion at sni.rs:161 would regress from the deleted C's behavior.

How to fix

  • sni.rs:164: change to /// Wildcard-aware lookup (same traversal as resolve); returns an OWNED reference (caller unrefs) — docs/cabi.md §1.6.
  • ffi.rs:714: drop "exact-pattern" — e.g. /// `us_listen_socket_find_server_name_ctx`: wildcard-aware SNI lookup
  • Do not apply the CodeRabbit "exact-match traversal" suggestion at sni.rs:161.

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

fix the merge conflicts

@robobun

robobun commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Merged main (ab20e85). Two conflicts resolved:

  • src/runtime/napi/napi_body.rs: kept main's while ... && !self.is_closing() loop condition and this PR's event_loop_alive check inside the body.
  • test/bundler/native-plugin.test.ts: kept main's .env({...bunEnv, ...}) form (both sides were doing the same crash-report suppression).

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

Current head's only real reds are the two connect-memleak GC tests. Verification on this exact tree: debug 8/8, debug with CI env (BUN_GARBAGE_COLLECTOR_LEVEL=1, BUN_JSC_randomIntegrityAuditRate=1.0) 4/4, fresh release build with the same env 6/6 — plus the earlier run of the exact CI artifact in an emulated Alpine arm64 container (18/18). These tests have not failed outside the CI hosts under any reproduction attempt.

@robobun retry the failed jobs

@robobun

robobun commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Retriggered CI.

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

Pattern analysis across the last 7 builds: the recurring failures have converged to the connect-memleak pair (+ occasionally another allocation-heavy test like no-orphans), always on the last-finishing linux lanes, always with zero output captured — the process dies without printing an assertion failure. Combined with the reproduction record (18/18 on this tree across debug/CI-env/fresh-release, plus the exact CI artifact passing 18/18 in an emulated Alpine arm64 container), the failure signature fits the host OOM killer on memory-pressured runners: deliberately-allocating GC tests, SIGKILLed silently, only on lanes that inherit hosts already loaded by earlier jobs. That's checkable on the CI side via dmesg/journald on the affected hosts for oom-kill events during these jobs.

@robobun retry the failed jobs

@robobun

robobun commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Retriggered CI.

…s linguist-generated

src/bssl (bun_bssl) re-exports the vendored bssl-sys and hosts the committed
per-target bindings; bun_usockets consumes it, and bun_boringssl_sys can
migrate onto it as a follow-up. The generated wrapper files no longer count
toward the diff on GitHub.
`bun_bssl` (`src/bssl`, the tree's BoringSSL binding surface — consumed by
`bun_usockets`) re-exports the vendored `bssl-sys` crate
(`vendor/boringssl/rust/bssl-sys`) as the raw BoringSSL layer
(.rewrite-specs/tls-semantics.md Part 2d; api.md CHANGES 1). Upstream generates

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 The new committed src/bssl/bindings/README.md cites .rewrite-specs/tls-semantics.md at line 6 ("(.rewrite-specs/tls-semantics.md Part 2d; api.md CHANGES 1)") and again at line 41 ("Decision (tls-semantics.md OQ-4/OQ-5)") — but this same PR adds .rewrite-specs/ to .gitignore (below the existing /specs/ entry commented "Kept locally for the ongoing work; not part of the source tree"), so no reader will ever have that file. Same class as the already-fixed stale-comment rounds (#4/#8/#13) and the still-open #16/#17, but a distinct pattern (gitignored working notes, not deleted files) their grep patterns wouldn't find. No runtime effect; drop both parentheticals — the sentences read fine without them.

Extended reasoning...

What the issue is

src/bssl/bindings/README.md is a new file added by this PR (per the diff and .gitattributes hunk that references it). Two lines cite a working-notes file that this same PR gitignores:

  • Line 6: (.rewrite-specs/tls-semantics.md Part 2d; api.md CHANGES 1) — a parenthetical citation appended to the sentence describing what bun_bssl re-exports.
  • Line 41: Decision (tls-semantics.md OQ-4/OQ-5): bindings are vendored outputs rather than a build-time bindgen step — citing open-question numbers from the same working-notes file.

Meanwhile, this PR's .gitignore hunk adds .rewrite-specs/ immediately below the existing /specs/ entry, which carries the comment "Kept locally for the ongoing work; not part of the source tree":

 # Web Streams rewrite working notes (design docs, spec transcription, review logs).
 # Kept locally for the ongoing work; not part of the source tree.
 /specs/
+.rewrite-specs/

So a committed README references a working-notes file that (a) does not exist in the repo (ls .rewrite-specs/ → No such file or directory), (b) is explicitly gitignored by this same PR, and (c) no reader — reviewer or future maintainer — will ever have.

Why the earlier fix passes missed it

This PR has already accepted and fixed ~5 rounds of the same "development-history narration in committed docs" class: #4 (lib.rs:12-14 / cabi.rs:12-16), #8 (event_loop/README.md → epoll_kqueue.c), #13 (lib.rs:40 → "feature-gated OFF"), and the still-open #16 (deleted C filenames: epoll_kqueue.c, bsd.c) / #17 (deleted Rust crate names: bun_uws, bun_uws_sys, uws_sys/SocketKind). But this is a distinct pattern: not a reference to a deleted file but to a gitignored local working-notes directory that this PR itself gitignores. The grep patterns from #16 (epoll_kqueue|bsd\.c) and #17 (bun_uws\b|bun_uws_sys|uws_sys/SocketKind) would not match rewrite-specs or tls-semantics. Verified: rg 'rewrite-specs' src/ packages/ → single hit at README.md:6; rg 'tls-semantics' src/ → hits at README.md:6 and README.md:41 only.

Impact

No runtime effect — pure doc staleness, hence nit. The concrete downside: a reader trying to understand why bun_bssl was structured this way ("why vendored bindings instead of build-time bindgen?") is told the rationale lives in .rewrite-specs/tls-semantics.md Part 2d and OQ-4/OQ-5 — a file they cannot find. Per CLAUDE.md "Comments carry only durable non-obvious content: … no bug history — that belongs in the PR description", these citations are development-phase narration that belongs in the PR description (which already covers this decision under "Approach"), not in-tree.

Step-by-step proof

  1. sed -n '6p' src/bssl/bindings/README.md(.rewrite-specs/tls-semantics.md Part 2d; api.md CHANGES 1). Upstream generates
  2. sed -n '41p' src/bssl/bindings/README.mdDecision (tls-semantics.md OQ-4/OQ-5): bindings are vendored outputs rather
  3. This PR's .gitignore diff: +.rewrite-specs/ at line 219, immediately below the /specs/ entry commented "Kept locally for the ongoing work; not part of the source tree".
  4. ls .rewrite-specs/No such file or directory — the directory does not exist in the checkout.
  5. rg 'rewrite-specs|tls-semantics' src/ packages/ → only src/bssl/bindings/README.md (lines 6 and 41). No other file references it.
  6. The grep patterns from open comments Fix browser map #16 (epoll_kqueue.c, bsd.c, SocketKind.rs) and Fix JSX parser bug: // comment after tagName and before closing tag is broken #17 (bun_uws\b|bun_uws_sys|uws_sys/SocketKind) do not match either string, so this is not a duplicate.

How to fix

Drop both parentheticals — the sentences read fine without them:

  • Line 6: (vendor/boringssl/rust/bssl-sys) as the raw BoringSSL layer. Upstream generates (delete (.rewrite-specs/tls-semantics.md Part 2d; api.md CHANGES 1)).
  • Line 41: Bindings are vendored outputs rather than a build-time bindgen step (delete Decision (tls-semantics.md OQ-4/OQ-5): prefix, capitalize "bindings").

The actual rationale ("no bindgen/libclang toolchain dependency in the build, and the committed diff makes fork drift reviewable on bumps") is already stated in the same paragraph, so nothing is lost.

Comment on lines +52 to +58
wrap_c="$(mktemp --suffix=.c)"
(cd "$BORINGSSL" && bindgen rust/bssl-sys/wrapper.h \
-o "$OUT_DIR/wrapper_$triple.rs" \
"${BINDGEN_ARGS[@]}" \
--wrap-static-fns-path "$wrap_c" \
-- -I "$BORINGSSL/include" --target="$triple" "$@")
sed -i "1i $STAMP" "$OUT_DIR/wrapper_$triple.rs"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 regenerate.sh uses GNU-only syntax that fails on stock macOS: line 52 mktemp --suffix=.c (BSD mktemp has no --suffix) and line 58 sed -i "1i $STAMP" (BSD sed needs -i '' and 1i\<newline>text). The script's defaults strongly imply a Linux host, but the header doesn't say so and README.md tells maintainers to fold this into the upgrade-boringssl flow — worth either a "# run on Linux (GNU coreutils/sed)" line in the header, or the portable rewrites (mktemp + mv for the suffix; printf + cat > tmp && mv instead of sed -i 1i).

Extended reasoning...

What the issue is

Two GNU-coreutils-only invocations in src/bssl/bindings/regenerate.sh fail on stock macOS/BSD:

  • Line 52: wrap_c="$(mktemp --suffix=.c)" — BSD/macOS mktemp has no --suffix option (only -t prefix and a template argument). Fails with mktemp: illegal option -- - on the very first gen() call.
  • Line 58: sed -i "1i $STAMP" ... — two GNU-isms: bare -i (BSD sed requires an explicit backup-extension argument, so it consumes "1i $STAMP" as the backup suffix and then errors on the filename-as-script), and the one-line Ni text insert form (BSD requires 1i\<newline>text).

The script header (lines 1-10) documents required tools (bindgen-cli, vendor/boringssl, vendor/zig, MACOS_SDK, WINSYSROOT) but does not state a Linux-only host requirement, and README.md says regeneration "Must be re-run on every BoringSSL commit bump … fold into the upgrade-boringssl flow" — a workflow a macOS maintainer may run.

Addressing the refutation

One verifier argued this is intentional/below-threshold because the script's defaults (WINSYSROOT=/opt/winsysroot, MACOS_SDK=$HOME/.bun/build-cache/MacOSX*.sdk, hermetic zig libc headers with -nostdinc) unambiguously target a Linux cross-generation host, and a macOS user hitting mktemp: illegal option would immediately know to run on Linux or brew install coreutils gnu-sed.

That's a fair read of the design intent, and it's exactly why this is nit severity, not normal. But three points keep it above the filing threshold:

  1. The intent is undocumented. The header lists five prerequisites and two env overrides but never says "run on Linux". mktemp: illegal option -- - is not self-explanatory — it says nothing about GNU vs BSD, and a maintainer following README.md's instruction to "re-run on every BoringSSL bump" wastes a debugging cycle before discovering the host constraint.
  2. The MACOS_SDK default is ambiguous, not dispositive. $HOME/.bun/build-cache/ is where Bun's build tooling caches artifacts on every platform, including macOS — a macOS dev who has run bun bd may well have an SDK there. It reads as "cross-gen from Linux" only if you already know that's the intent.
  3. This PR has already accepted ~15 nits of exactly this class (stale comments, wrong hand-coded constants, undocumented host assumptions in maintainer-only scripts). The bar this PR's review has established is "if a one-line fix removes a maintainer papercut, it's worth flagging" — and this is a one-line fix.

The refutation's point about sort -V (line 30) being another GNU-ism is weaker than stated: macOS sort has supported -V since 10.15 and FreeBSD since 12.0, so it doesn't add to the case.

Why nothing prevents it

set -euo pipefail (line 11) means the script exits loudly on the first failing command — so there is zero risk of committing corrupted output. That's precisely why this is a nit and not a normal-severity finding: the failure mode is a cryptic error, not silent bad bindings.

Impact

Maintainer-only, run rarely (once per BoringSSL bump), outputs pre-committed. Nothing user-facing. The only cost is a macOS maintainer following README.md's instruction, hitting mktemp: illegal option -- -, and having to reverse-engineer that the script assumes GNU coreutils.

Step-by-step proof

  1. On stock macOS (any version — Apple ships BSD mktemp/sed, not GNU): cd src/bssl/bindings && ./regenerate.sh.
  2. Line 52 executes for the first target (x86_64-unknown-linux-gnu): mktemp --suffix=.c.
  3. BSD mktemp parses --suffix=.c: sees -, then - again → mktemp: illegal option -- -, exits nonzero.
  4. set -e propagates; the subshell substitution fails; script exits. No target is generated.
  5. If a user works around line 52 (e.g. gmktemp), line 58 fails next: BSD sed -i "1i // BoringSSL commit: ..." file.rs treats "1i // BoringSSL..." as the backup-suffix argument to -i, then tries to interpret file.rs as the sed script → sed: 1: "...wrapper_x86_64-unknown-l ...": invalid command code w (or similar).

How to fix

Minimal: add one line to the header comment (after line 4), e.g. # Host: Linux (uses GNU mktemp --suffix and GNU sed -i).

Portable (if macOS support is wanted):

  • Line 52: wrap_c="$(mktemp)"; mv "$wrap_c" "$wrap_c.c"; wrap_c="$wrap_c.c" — or just drop the suffix (bindgen's --wrap-static-fns-path doesn't require .c).
  • Line 58: { printf '%s\n' "$STAMP"; cat "$OUT_DIR/wrapper_$triple.rs"; } > "$OUT_DIR/wrapper_$triple.rs.tmp" && mv "$OUT_DIR/wrapper_$triple.rs.tmp" "$OUT_DIR/wrapper_$triple.rs"

Either is fine; the header comment is the smallest change consistent with the script's evident Linux-cross-generation design.

Connect errors: the core now closes a failed direct-connect socket before
notifying the consumer (the old shim layer's contract; two consumers had
regressed to never closing, leaving the dead socket armed in level-triggered
epoll - a failed redis:// or ws:// connect leaked the fd and spun the event
loop at 100% CPU). Consumer closes remain idempotent no-ops; postgres/mysql
regain close-before-notify ordering. Regression tests assert bounded CPU and
no fd growth across repeated failed connects.

Aliasing soundness: completed the raw-place conversion past the crate
boundary - FilePoll registration/arm/activate, keep-alive, jsc loop
accounting, spawn pid-fd watch, and dns machport registration no longer form
whole-struct &mut Loop while foreign threads fetch_add pending_wakeups; the
&mut accounting methods are deleted so the pattern cannot recur. HTTPThread's
cross-thread queues, ThreadSafeStreamBuffer, and napi threadsafe-function
entry points converted off cross-thread &mut. Worker shutdown gained rundown
protection (terminating flag + external-post counter drained before VM
dealloc) closing the wakeup-after-free race; TSFN calls after VM death now
return napi_closing instead of silently leaking with napi_ok.

close_all walks: the group walk restarts from the head instead of probing a
cached pointer a GC-finalized listener can free mid-walk; the graceful socket
walk snapshots the list under the tick-depth bracket (single-pass - was
quadratic in TLS-deferred closes, 2x shutdown time at 8k idle TLS conns) and
revalidates before each dispatch, fixing a graceful-to-RST downgrade under
re-entrant adoption; the connecting walk restarts from head and the force
drain now covers connecting sockets.

Build: linker orderfile is invalidated when its symbol set no longer matches
(the renamed socket core made inherited orderfiles silently no-op, costing
+7.7MB resident text - the entire RSS delta vs main); dead C-side fault
injection define removed.

Cleanup: crate-wide dead_code allow removed with ~25 dead items deleted
(including an unreachable depth-0 TLS entry point); duplicated helpers
consolidated (twin retirement, IPC decode loop, would-block/errno module,
TLS side-channel guard); test hardening (in-process servers instead of live
DNS, awaited conditions, success counters, exact crash-message assertions).
Comment thread src/http/HTTPThread.rs
Comment on lines +97 to +99
/// loop exists; null before that. Cross-thread `wakeup()` Acquire-loads it,
/// which also publishes the loop's initialization.
static UWS_LOOP: AtomicPtr<uws::Loop> = AtomicPtr::new(core::ptr::null_mut());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 The comment at init_once (HTTPThread.rs:1210-1212, outside the diff) still says "can fill in loop_/uws_loop/contexts" and "no other thread reads HTTP_THREAD until has_awoken is set in on_start", but this PR removes both the has_awoken: AtomicBool and uws_loop: *mut uws::Loop struct fields (moved to the UWS_LOOP AtomicPtr / HTTP_THREAD_INIT module statics) — grep confirms line 1212 is the sole remaining has_awoken reference in src/. The parallel HttpThread::new() doc comment at lines 167-169 was updated ("loop_ (and the UWS_LOOP static)"), so this is a missed sibling. Same stale-comment class as #4/#8/#13 and still-open #16/#17, but a distinct pattern (removed struct fields from the field-to-static refactor, not deleted files/crates) their grep patterns wouldn't catch. No runtime effect; drop uws_loop from the fill-in list and reword the SAFETY line to reference HTTP_THREAD_INIT. (Filed at the field-removal hunk because line 1212 has no commentable diff range.)

Extended reasoning...

What the issue is

The comment at src/http/HTTPThread.rs:1207-1212, inside init_once (outside any diff hunk), reads:

fn init_once(opts: &InitOpts) {
    // Initialize the global (with timer
    // started on the calling thread) BEFORE spawning, so `on_start`'s
    // `crate::http_thread_mut()` finds `Some(..)` and can fill in
    // `loop_`/`uws_loop`/contexts.
    // SAFETY: `init_once` runs under `Once`; no other thread reads
    // `HTTP_THREAD` until `has_awoken` is set in `on_start`.
    unsafe {
        (*crate::HTTP_THREAD.get()).write(HttpThread::new());
    }
    crate::HTTP_THREAD_INIT.store(true, core::sync::atomic::Ordering::Release);

Both uws_loop (as an HttpThread field) and has_awoken are removed by this PR. The diff shows:

  • - pub uws_loop: *mut uws::Loop, — replaced by the module-level static UWS_LOOP: AtomicPtr<uws::Loop> at line 99.
  • - pub has_awoken: AtomicBool, — replaced by the HTTP_THREAD_INIT gate (the .store(true, Release) on line 1216, four lines below the stale comment).
  • - // Release: publishes uws_loop/loop_ to cross-thread wakeup() readers (which Acquire-load has_awoken). and - thread.has_awoken.store(true, Ordering::Release); — the mechanism the SAFETY comment describes was deleted from on_start.

rg has_awoken src/ returns exactly one hit — line 1212 itself — confirming the identifier no longer exists anywhere else.

Why nothing prevents it

It is a // comment — nothing enforces it. The diff did update the parallel comment at HttpThread::new() (lines 167-169 now correctly read "loop_ (and the UWS_LOOP static) are filled in by on_start"), so the author was aware of the class; this second instance ~1000 lines below was missed in the same pass.

Relationship to previous comments

This PR has already accepted and fixed ~7 rounds of the same "development-history narration in comments" class: #4 (lib.rs/cabi.rs), #8 (event_loop/README.md), #13 (lib.rs:40), and the still-open #16 (deleted C filenames) / #17 (deleted Rust crate names). This is a distinct instance: it references removed struct fields introduced by this PR's field-to-static refactor (per the diff, the HttpThread struct dropped uws_loop/has_awoken and the state moved to module statics UWS_LOOP/HTTP_THREAD_INIT), not deleted files or crates — so the grep patterns from #16 (epoll_kqueue|bsd\.c|SocketKind) and #17 (bun_uws\b|bun_uws_sys|uws_sys/SocketKind) would not match has_awoken or uws_loop. Not a duplicate.

Impact

No runtime effect — pure comment staleness, hence nit. The concrete downside: this is a SAFETY comment justifying an unsafe block, and it names the wrong synchronization primitive. A reader auditing the unsafe { (*crate::HTTP_THREAD.get()).write(...) } for data races would look for has_awoken in on_start (which no longer exists), not HTTP_THREAD_INIT (the actual gate on line 1216, right below). The actual invariant is still sound — only the description is wrong. Per CLAUDE.md "Comments carry only durable non-obvious content: invariants, ownership/lifetime contracts, SAFETY justifications" — a SAFETY comment that names a nonexistent field is exactly the kind of drift that rule targets.

Step-by-step proof

  1. sed -n '1210,1212p' src/http/HTTPThread.rs at HEAD ee37e3a:
    // `loop_`/`uws_loop`/contexts.
    // SAFETY: `init_once` runs under `Once`; no other thread reads
    // `HTTP_THREAD` until `has_awoken` is set in `on_start`.
    
  2. rg has_awoken src/ → single hit: src/http/HTTPThread.rs:1212. The field is gone from all code.
  3. PR diff at HTTPThread.rs: - pub uws_loop: *mut uws::Loop, and - pub has_awoken: AtomicBool, removed from the HttpThread struct; +static UWS_LOOP: AtomicPtr<uws::Loop> added at line 99; - thread.has_awoken.store(true, Ordering::Release); removed from on_start.
  4. sed -n '167,169p' src/http/HTTPThread.rs → the parallel HttpThread::new() doc comment was updated in this PR: "loop_ (and the UWS_LOOP static) are filled in by on_start". So the author touched one of the two comments describing this state; line 1210-1212 is the missed sibling.
  5. Line 1216 (crate::HTTP_THREAD_INIT.store(true, Release)) is the actual publish gate the SAFETY comment should name.
  6. The still-open Fix browser map #16/Fix JSX parser bug: // comment after tagName and before closing tag is broken #17 grep patterns match neither has_awoken nor uws_loop, so this is not covered by them.

How to fix

// Initialize the global (with timer started on the calling thread) BEFORE
// spawning, so `on_start`'s `crate::http_thread_mut()` finds `Some(..)`
// and can fill in `loop_` (and the `UWS_LOOP` static)/contexts.
// SAFETY: `init_once` runs under `Once`; no other thread reads
// `HTTP_THREAD` until `HTTP_THREAD_INIT` is Release-stored below.

— i.e., mirror the already-updated HttpThread::new() comment for the fill-in list, and point the SAFETY line at HTTP_THREAD_INIT (the store on line 1216) instead of the removed has_awoken.

(Filed at the field-removal hunk because line 1212 has no commentable diff range.)

Comment thread Cargo.toml
"src/shell_parser",
"src/tcc_sys",
"src/uws_sys",
"src/usockets",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 🟡 Companion to still-open #19 (src/bssl/bindings/README.md.rewrite-specs/tls-semantics.md): three more gitignored working-notes references at src/usockets/Cargo.toml — line 26 (protocol.rs; safe-protocol.md), line 28 (consumers/04), line 31 (tls-semantics.md Part 2d). None exist in-tree (src/usockets/docs/ has only cabi.md/design.md/semantics.md/tls.md; .rewrite-specs/ is gitignored by this PR at .gitignore:219), and two of the three (safe-protocol.md, consumers/04) are NOT caught by #19's suggested rewrite-specs|tls-semantics grep. Same class as #4/#8/#13/#16/#17/#19/#21; no runtime effect. Fix: drop the three parentheticals — the sentences read fine without them. (Filed against workspace Cargo.toml because the new src/usockets/Cargo.toml file has no commentable diff line ranges.)

Extended reasoning...

What the issue is

src/usockets/Cargo.toml is a new file added by this PR. Three of its dependency comments cite working-notes files that do not exist in the committed tree:

  • Line 26: # Protocol v2 owner refcounting (protocol.rs; safe-protocol.md).safe-protocol.md does not exist. src/usockets/docs/ contains only cabi.md, design.md, semantics.md, tls.md (verified via ls).
  • Line 28: # Platform-split addrinfo type shared with the DNS bridge (consumers/04). — no consumers/ directory exists anywhere in src/usockets/ or the repo root.
  • Line 31: # Raw BoringSSL bindings (tls-semantics.md Part 2d): re-export of the vendoredtls-semantics.md does not exist in-tree; it lives in .rewrite-specs/, which this same PR adds to .gitignore at line 219.

All three are references into the author's local .rewrite-specs/ working-notes directory, which the PR itself gitignores (below the existing /specs/ entry commented "Kept locally for the ongoing work; not part of the source tree"). No reader — reviewer or future maintainer — will ever have those files.

Relationship to still-open comment #19

Comment #19 (still unresolved, filed at src/bssl/bindings/README.md:6) covers the same "gitignored working notes" pattern class at a different filesrc/bssl/bindings/README.md lines 6 and 41, both citing tls-semantics.md. This finding is a companion at a distinct location (src/usockets/Cargo.toml), and critically: two of the three references here would NOT be caught by #19's suggested grep pattern. #19 recommends rg 'rewrite-specs|tls-semantics' src/ packages/; that catches line 31 but misses safe-protocol.md (line 26) and consumers/04 (line 28). So a fix pass addressing #19 would leave lines 26 and 28 stale.

Verified: rg 'safe-protocol|consumers/0[0-9]|tls-semantics' src/ packages/ hits only src/usockets/Cargo.toml (3 lines) and src/bssl/bindings/README.md (2 lines, covered by #19).

Why nothing prevents it

These are # TOML comments — nothing enforces them. This is the same "development-history narration in committed docs" class the PR has already accepted and fixed ~7 rounds of (#4 lib.rs/cabi.rs, #8 event_loop/README.md, #13 lib.rs:40, #16 deleted C filenames, #17 deleted Rust crate names, #19 gitignored .rewrite-specs, #21 removed struct fields), all of which the author has fixed or acknowledged. The bar this PR's review has established is clear: dangling references to nonexistent/gitignored files in committed docs are worth flagging as nits.

Impact

No runtime effect — pure comment staleness, hence nit. The concrete downside: a reader trying to understand why bun_ptr / bun_dns / bun_bssl are dependencies of the new socket crate is pointed at three files they cannot find. Per CLAUDE.md "Comments carry only durable non-obvious content: … no bug history — that belongs in the PR description". The crate's own docs/ directory (design.md, cabi.md) already carries the durable references; the parentheticals add nothing a checked-out reader can follow.

Step-by-step proof

  1. sed -n '26p' src/usockets/Cargo.toml# Protocol v2 owner refcounting (protocol.rs; safe-protocol.md).
  2. ls src/usockets/docs/cabi.md design.md semantics.md tls.md. No safe-protocol.md anywhere in the crate or repo.
  3. sed -n '28p' src/usockets/Cargo.toml# Platform-split addrinfo type shared with the DNS bridge (consumers/04).
  4. ls src/usockets/consumers/ → No such file or directory. find . -name '04*' -path '*consumers*' → nothing.
  5. sed -n '31p' src/usockets/Cargo.toml# Raw BoringSSL bindings (tls-semantics.md Part 2d): re-export of the vendored
  6. ls .rewrite-specs/ → No such file or directory. This PR's .gitignore:219 adds .rewrite-specs/.
  7. test #19's grep pattern rewrite-specs|tls-semantics matches line 31 but NOT lines 26 or 28 — so this is not a duplicate; fixing test #19 alone leaves two of the three references stale.

How to fix

Drop the three parentheticals — the sentences read fine without them:

  • Line 26: # Protocol v2 owner refcounting (protocol.rs).
  • Line 28: # Platform-split addrinfo type shared with the DNS bridge.
  • Line 31: # Raw BoringSSL bindings: re-export of the vendored

The protocol.rs reference on line 26 is fine to keep (that file exists at src/usockets/protocol.rs); only the ; safe-protocol.md suffix is dead.

(Filed against workspace Cargo.toml:90 because the new src/usockets/Cargo.toml file has no commentable diff line ranges — same convention every other new-file finding on this PR has used.)

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

Triage of the new asan-lane SIGABRT (test-worker-message-port-transfer-terminate.js): pre-existing, not from this branch. A/B on the CI asan artifacts under identical load: this head 117/320 aborts vs the previous head 103/320 — same rate, identical assertion (!scope.exception() || !result in JSObject::getOwnPropertyDescriptor). The MessagePort transfer is incidental — a minimal worker.terminate() racing script startup reproduces without any ports. Root cause is in JSC: DeferTermination throws the TerminationException from its destructor after a property lookup already succeeded; JSObject::get tolerates this upstream but three sibling sites don't. Fix opened as oven-sh/WebKit#286 (verified 0/320 + 0/240 after vs 3/320 before); it reaches this repo via the next WebKit version bump, along with a stress regression test held back until then (the test aborts on unfixed assertion builds).

The dead-code-escapes failure was an inventory update for two justified platform-split allows — fixed in b061f12.

// `JsCell` and callers do not hold the borrow across JS re-entry that
// touches `ipc_data` itself.
unsafe { self.ipc_data.get_mut() }.as_mut()
// SAFETY: single JS-mutator thread; the heap `IpcData` outlives this

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we dont need safety comments if we are not using unsafe

// so `&mut Store` is materialised only *after* `&mut self` is retired
// inside `deinit_possibly_defer` (via `file_polls_mut()`).
let loop_ = vm.loop_mut();
let loop_ = vm.loop_();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

loop_ is not a good name IMO

@alii

alii commented Aug 15, 2026

Copy link
Copy Markdown
Member

@robobun rebase

@robobun

robobun commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

Tried to bring this up to date with main; stopping to flag scope before touching anything. Since the last sync (b4045c17b6, Jul 12), main has moved 1045 commits. A trial merge produced 126 conflicts, and the shape of them is the problem, not the count:

~30 are modify/delete on files this PR deletes. Main landed 34 commits that modify the C usockets core this PR removes (socket.c, loop.c, bsd.c, udp.c, openssl.c, epoll_kqueue.c, libuv.c, ...): +2119/-400 lines, plus 24 commits (+672/-875) to the src/uws_sys/*.rs layout crate that is also deleted. These are behavioral fixes that have no merge-able counterpart in the tree; each one has to be re-implemented inside the Rust crate. Representative set:

Some of these the rewrite may already cover by construction (the PR body calls out generation-checked handles and core-owned close ordering, which plausibly subsumes #36467 and #37661), but deciding that per-fix and porting the rest is design work on the crate itself, not something I should do by picking a side of a conflict marker.

The other ~95 are content conflicts in consumer files (HTTPThread.rs, HTTPContext.rs, socket_body.rs, Listener.rs, VirtualMachine.rs, web_worker.rs, napi_body.rs, the sql_jsc drivers, valkey, bake, etc.), where main's 335 commits to those directories (incl. the worker-lifetime rework in #37075) overlap the protocol-v2 migration. Those are resolvable but each needs the rewrite's ownership model understood to resolve correctly.

I have not pushed anything. @Jarred-Sumner this is effectively a month of upstream usockets work to re-port into the crate; seems like your call how to sequence it. Happy to take the mechanical consumer-file conflicts once the deleted-file fixes have been ported, or to do a merge that takes HEAD for the deleted files and leaves the port list above as a checklist, if that is the preferred workflow. Say which.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants