deps: update sqlite to 3.53.400 - #5
Open
github-actions[bot] wants to merge 1 commit into
Open
Conversation
github-actions
Bot
force-pushed
the
deps/update-sqlite
branch
from
March 15, 2026 06:17
01a2084 to
e960c93
Compare
igorls
pushed a commit
that referenced
this pull request
Apr 9, 2026
Fixes a segfault when reading `.fd` on the result of `Bun.listen({ tls:
{ ... } })`.
`Listener.getFD` was calling `uws_listener.socket(true).fd()` for TLS
listeners. For `is_ssl=true`, the uSockets wrapper
`us_internal_ssl_socket_get_native_handle` returns `s->ssl`, and `fd()`
then calls `SSL_get_fd()` on it. But a listen socket has no SSL object —
SSL is per-connection — so `s->ssl` is uninitialized memory (ASAN poison
`0xbebebe...`) and the call segfaults.
Listen sockets always have a plain poll fd regardless of TLS, so get it
via the non-SSL path.
```
#3 SSL_get_rfd (ssl=0xbebebe0000000018)
#4 SSL_get_fd (ssl=0xbebebe0000000018)
#5 deps.uws.socket.NewSocketHandler(true).fd () at src/deps/uws/socket.zig:283
bun.js.api.bun.socket.Listener.getFD at src/bun.js/api/bun/socket/Listener.zig:532
```
Repro (also triggered when `console.log()` introspects the listener):
```js
const s = Bun.listen({
hostname: "localhost", port: 0,
socket: { data(){}, open(){}, close(){} },
tls: { passphrase: "abc" },
});
console.log(s.fd);
```
Found by Fuzzilli.
---------
Co-authored-by: robobun <robobun@users.noreply.github.com>
github-actions
Bot
force-pushed
the
deps/update-sqlite
branch
from
April 12, 2026 06:28
e960c93 to
3967cfd
Compare
igorls
pushed a commit
that referenced
this pull request
May 6, 2026
…en-sh#29910) ## What `Blob.dupeWithContentType` guarded its content_type handling on `duped.isHeapAllocated()` immediately *after* calling `duped.setNotHeapAllocated()`, so both branches were dead. When the source Blob's `content_type` is heap-allocated, the bitwise-copied dupe aliased the same allocation while both sides had `content_type_allocated == true`. This is a regression from oven-sh#23015: the pre-refactor code checked `duped.allocator != null` *before* clearing it at the end of the function; the refactor moved the clear to the top but left the (renamed) guard in place. ## Repro ```js const file = Bun.file(path, { type: "application/x-custom-type-not-in-registry-abcdefghijklm" }); const response = new Response(file); // body holds a dupe that aliases file.content_type await file.write("hello", { type: "application/x-..." }); // frees file.content_type response.headers.get("content-type"); // reads freed memory ``` On ASAN builds: ``` ==716==ERROR: AddressSanitizer: use-after-poison on address 0x71df454301c0 #1 in Zig::toStringCopy(ZigString) helpers.h:217 #2 in WebCore__FetchHeaders__put bindings.cpp:2082 #5 in bun.js.webcore.Response.getOrCreateHeaders Response.zig:358 ``` On release builds the freed slot gets reused and the read produces garbage: ``` TypeError: Header '25' has invalid value: 'ion/x-custom-type-not-in-registry-abcdefghijklm' ``` ## Fix Drop the `isHeapAllocated()` guard and always deep-copy an allocated `content_type` in `dupeWithContentType`. The old `!include_content_type` branch's "resolve to static mime or fall back to empty" is gone — it would have dropped FormData's `multipart/form-data; boundary=...` (and any non-registry type) on `Response.clone()`, and the branch itself was marked `// TODO: fix this / this is a bug`. The `include_content_type` parameter is now a no-op. Since every dupe now owns its `content_type` copy, `Blob.deinit()` frees it. That in turn required closing a few places that held a bitwise-copied Blob alongside the live owner: - `fromJSWithoutDeferGC` `move=true`: deep-copy `name`/`content_type` into the moved-out value so the source JS Blob keeps sole ownership; the BuildArtifact arm now `dupe()`s (its "move" only nulled the store on a local copy). - `getSliceFrom()`: free the dupe's copy before overwriting it with the slice's own type. - `doWrite`/`getWriter`: clear `content_type_allocated` after the in-place free so a registry-resolved static string isn't later freed by `deinit()`. - `BlobOrStringOrBuffer.deinitAndUnprotect`: only deref the store (matching its `deinit()`) since `.blob` is a raw view of a live JS Blob. ## Verified - `bun bd test test/js/web/fetch/blob.test.ts` — 16/16 pass - New UAF test fails on both debug/ASAN (use-after-poison) and system bun (garbage header) without the fix, passes with it - New clone test guards against dropping FormData's boundary on `Response.clone()` - ASAN stress: 1k× `Response.clone`/`blob.slice`/`createObjectURL`+revoke/`new Response([blob])`/`write({type})` — no double-free - RSS is flat across 50k × 1KB-type `Response.clone()` and `blob.slice()` --------- Co-authored-by: robobun <robobun@users.noreply.github.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
igorls
pushed a commit
that referenced
this pull request
May 6, 2026
…es (oven-sh#30077) ## What When a chunked (or HTTP/3) request body exceeds `maxRequestBodySize`, `onBufferedBodyChunk` writes the 413 directly on the raw uWS response: ```zig resp.writeStatus("413 Payload Too Large"); resp.endWithoutBody(comptime !http3); ``` `internalEnd` → `markDone()` nulls `onAborted`, so when the socket closes no abort ever fires to detach `ctx.resp` or release the base ref. `this.resp` is left pointing at a completed response whose socket is about to be freed by `us_internal_free_closed_sockets`. If the fetch handler returned a pending Promise: - **resolve**: `handleResolve` → `isAbortedOrEnded()` is false (`this.resp != null`) → `render()` → `runCorkedWithType` corks the freed socket → **heap-use-after-free** (ASAN trace below). - **reject**: `handleReject` reads `resp.hasResponded()` off freed memory, sees `true`, skips the error handler, and returns without ever releasing the base ref → **RequestContext leaks** (`server.pendingRequests` never returns to 0). ## Fix Route through `this.endWithoutBody()` (the `RequestContext` wrapper) instead of the raw `resp.endWithoutBody()`. That path does `detachResponse()` (nulls `this.resp`, clears `onData`/`onAborted`/`onTimeout`) and `deref()` (releases the base ref), matching every other end path in this file. The body promise is rejected with the specific `"Request body exceeded maxRequestBodySize"` error *before* `endWithoutBody()` so `endRequestStreaming()` doesn't overwrite it with a generic `ConnectionClosed`. `has_written_status` is set so any later `renderMissing`/`renderMetadata` knows the status line is already committed. ## Repro ``` ==ERROR: AddressSanitizer: heap-use-after-free #0 us_socket_group socket.c:77 #1 uWS::AsyncSocket<false>::getLoopData() AsyncSocket.h:69 #2 uWS::AsyncSocket<false>::isCorked() AsyncSocket.h:141 #3 uWS::HttpResponse<false>::cork(...) HttpResponse.h:647 #4 uws_res_cork libuwsockets.cpp:1740 #5 ...runCorkedWithType Response.zig:299 #6 ...doRenderBlob RequestContext.zig:1942 ... oven-sh#11 ...handleResolve RequestContext.zig:220 oven-sh#12 ...onResolve RequestContext.zig:154 freed by: #1 us_poll_free epoll_kqueue.c:73 #2 us_internal_free_closed_sockets loop.c:305 ``` ## Test `test/js/bun/http/serve-pending-promise-abort-leak.test.ts` — new case sends a raw `Transfer-Encoding: chunked` POST exceeding `maxRequestBodySize` with a handler that holds its resolve/reject, waits for the socket to be reclaimed, then settles the Promise. Asserts `pendingRequests` returns to 0 for both paths, the body was rejected with the right message, and a follow-up request still works. Without the fix: ASAN heap-use-after-free on the resolve path; on release builds the reject path shows `pendingAfterReject: 1` (leak). Co-authored-by: robobun <robobun@users.noreply.github.com>
igorls
pushed a commit
that referenced
this pull request
May 6, 2026
…ven-sh#30136) ## Repro ```js const client = await Bun.connect({ hostname, port, tls, socket: { ... } }); // after handshake: client.end("x"); client.flush(); // ← second markInactive frees *Handlers // peer replies close_notify → onClose derefs freed Handlers ``` ASAN on debug build: ``` ==4075==ERROR: AddressSanitizer: use-after-poison on address 0x7aff355e0469 READ of size 1 at 0x7aff355e0469 thread T0 #0 bun.js.api.bun.socket.NewSocket(true).onClose src/bun.js/api/bun/socket.zig:661:46 #1 deps.uws.handlers.PtrHandler(...).onClose src/deps/uws/handlers.zig:49:61 ... #5 us_internal_ssl_on_close packages/bun-usockets/src/crypto/openssl.c:940:29 ``` ## Cause `end()` → `internalFlush` → `canEndAfterFlush()` → `markInactive()` → `closeAndDetach(.normal)` detaches `this.socket` and calls `us_socket_close(code=0)`. For TLS with `code==0`, `us_internal_ssl_close` sends close_notify and **defers** the raw close until the peer replies (so the loop stays alive to receive it). `markInactive` returns early without clearing `is_active`, relying on the eventual `onClose` → `markInactive` to run `handlers.markInactive()` and free the client-mode `*Handlers`. `flush()` was the only `internalFlush()` caller without an `isDetached()` guard. Calling it in that window re-enters `canEndAfterFlush()` (still `is_active && end_after_flush`) → `markInactive()`, which now sees the detached socket as closed and runs the **full** teardown: `handlers.markInactive()` → `active_connections == 0` → `vm.allocator.destroy(handlers)`. When the peer's close_notify later arrives, `onClose` calls `this.getHandlers()` on freed memory. ## Fix Add the same `isDetached()` early-return to `flush()` that `end()`, `endBuffered()`, `onWritable`, and every other `internalFlush()` caller already have. ## Verification New test in `test/js/bun/net/socket.test.ts` spawns a TLS client that does `end("x"); flush(); flush();` after handshake and awaits `close`. - Without fix (`git stash -- src/`): subprocess aborts with the ASAN trace above; test fails. - With fix: subprocess prints `OK` and exits 0; test passes. Co-authored-by: robobun <robobun@users.noreply.github.com>
igorls
pushed a commit
that referenced
this pull request
May 6, 2026
…before write (oven-sh#30155) ## Repro ```js Bun.serve({ port: 0, fetch: () => new Response("hello", { headers: [ ["Transfer-Encoding", "gzip"], ["Transfer-Encoding", "chunked"], ], }), }); // HEAD / → ASAN heap-use-after-free in uWS::HttpResponse::writeHeader ``` The duplicate entries make `FetchHeaders` combine them via `makeString()`, producing a `StringImpl` held only by the header map — the minimal condition for the free to actually happen. StringImpl is allocated via bmalloc which ASAN doesn't instrument by default; with `Malloc=1` (bmalloc → system heap) the debug build reports: ``` AddressSanitizer: heap-use-after-free READ of size 13 #2 uWS::HttpResponse<false>::writeHeader #5 doRenderHeadResponse RequestContext.zig:1378 freed by: oven-sh#23 HTTPHeaderMap::remove oven-sh#28 doWriteHeaders RequestContext.zig:2303 oven-sh#29 renderMetadata RequestContext.zig:2209 oven-sh#30 doRenderHeadResponse RequestContext.zig:1377 ``` ## Cause `doRenderHeadResponse()` calls `headers.fastGet(.TransferEncoding)`, which returns a `ZigString` that **borrows** the header map entry's `StringImpl` bytes (no ref taken). For an ASCII value, `toSlice()` also borrows rather than copying. It then calls `this.renderMetadata()`, whose `doWriteHeaders()` does `headers.fastRemove(.TransferEncoding)` (and `renderMetadata` also `swapInitHeaders()` + `deref()`s the whole `FetchHeaders`). When the map held the only reference to the `StringImpl`, it's destroyed right there — and the very next line `resp.writeHeader("transfer-encoding", transfer_encoding_str.slice())` writes the freed bytes to the socket. The adjacent `Content-Length` branch has the same bug: `std.fmt.parseInt()` runs on the borrowed slice *after* `renderMetadata()` has already `fastRemove(.ContentLength)`'d it. ## Fix - **Transfer-Encoding**: use `toSliceClone()` instead of `toSlice()` so the value is owned and survives `renderMetadata()`. - **Content-Length**: parse the integer *before* `renderMetadata()` (and drop the slice immediately), so the borrowed bytes are never touched after the header entry is removed. No extra allocation needed since only the parsed `usize` is used afterwards. ## Verification New test in `test/js/bun/http/bun-server.test.ts` (inside the existing `HEAD requests oven-sh#15355` block) spawns a subprocess with `Malloc=1` (non-Windows), serves HEAD responses whose Transfer-Encoding / Content-Length values are `makeString()`-combined (sole-owner StringImpl), and asserts the raw wire output. ``` git stash push -- src/ → test fails with "AddressSanitizer: heap-use-after-free" in stderr git stash pop → test passes ``` All other tests in the `HEAD requests oven-sh#15355` describe block continue to pass. Co-authored-by: robobun <robobun@users.noreply.github.com>
github-actions
Bot
force-pushed
the
deps/update-sqlite
branch
from
May 10, 2026 06:50
3967cfd to
bf1e289
Compare
igorls
pushed a commit
that referenced
this pull request
May 31, 2026
…er (oven-sh#31333) ### Problem Fuzzing found a second transpiler stack overflow (`sig:SIGSEGV:nostack`): ~600 nested `{` blocks crash the process. ```js new Bun.Transpiler({ loader: "tsx", target: "bun", minifyWhitespace: true, deadCodeElimination: true }) .transformSync("{".repeat(600) + 'class Test1 { static "prop1" = 0; }' + "}".repeat(600)); ``` oven-sh#31242 guarded the **expression** recursion (`visit_expr_in_out`, `print_expr`, DCE helpers), but the **statement** recursion was left unguarded. Nested blocks stay under `MAX_STMT_DEPTH` (1000) in `parse_stmt`, then the visit pass recurses through `visit_stmts → visit_and_append_stmt → s_block → visit_stmts` with no stack check — each level stacks several multi-KB frames, so a few hundred levels exhaust the thread's stack (reproduces at depth 800 on a debug build's 8 MB main stack; smaller stacks crash at 600): ``` #5 visit_stmts src/js_parser/visit/mod.rs:1280 #6 s_block src/js_parser/visit/visit_stmt.rs:1627 #7 visit_and_append_stmt src/js_parser/visit/visit_stmt.rs:108 #8 visit_stmts src/js_parser/visit/mod.rs:1336 ... (repeats until SIGSEGV) ``` ### Fix Guard the statement recursion the same way the expression recursion already is: - `visit_and_append_stmt` now checks `stack_check.is_safe_to_recurse()` (plus the `reported_stack_overflow` fast-path) and reports "Maximum call stack size exceeded" instead of descending, mirroring `visit_expr_in_out`. - `print_stmt` and `print_if` (which self-recurses for `else if` chains without passing through `print_stmt`) get the same guard `print_expr`/`print_binding` already have, so a deep AST printed on a thread with less stack headroom errors instead of overflowing. - Removed the `MAX_STMT_DEPTH`/`parse_stmt_depth` hard cap from `parse_stmt` (review feedback): recursion depth in every phase is now governed by `StackCheck` alone, matching the Zig parser. - Guarded `hoist_symbols` the same way: it walks the scope tree before the visit pass at the full depth the parser allowed, and was only kept safe previously by the now-removed cap (the 15k-deep `lots-of-for-loop.js` fixture overflowed it in release builds otherwise). With this, every arbitrarily-nestable AST recursion (statements, expressions, bindings) is stack-checked in all three phases (parse, visit, print); deep inputs throw a catchable `Maximum call stack size exceeded` error. ### Verification New test `deeply nested statement blocks error instead of crashing the process` in `test/bundler/transpiler/transpiler.test.js` transpiles nested-block and `else if`-chain shapes at depths 600/800/990 (below the parse-time cap, deep enough to overflow an unguarded visitor) in a subprocess and asserts it exits cleanly. - Without the fix: the subprocess dies with SIGSEGV at depth 800+ (debug build), so the test fails. - With the fix: `bun bd test test/bundler/transpiler/transpiler.test.js` → 147 pass, 0 fail; the repro above now throws `Maximum call stack size exceeded`.
github-actions
Bot
force-pushed
the
deps/update-sqlite
branch
from
June 7, 2026 07:18
bf1e289 to
c02bb39
Compare
github-actions
Bot
force-pushed
the
deps/update-sqlite
branch
from
June 28, 2026 07:15
c02bb39 to
6e9d880
Compare
github-actions
Bot
force-pushed
the
deps/update-sqlite
branch
from
July 26, 2026 06:51
6e9d880 to
7940968
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Updates SQLite to version 3.53.400
Compare: https://sqlite.org/src/vdiff?from=3.51.2&to=3.53.400
Auto-updated by this workflow