Skip to content

Bump WebKit (oven-sh/WebKit#691 preview): restore the Vector capacity that WebKit 310668@main halved - #42982

Draft
robobun wants to merge 2 commits into
mainfrom
robobun/364a952c/fromutf8-null-buffer
Draft

robobun wants to merge 2 commits into
mainfrom
robobun/364a952c/fromutf8-null-buffer

Conversation

@robobun

@robobun robobun commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • Bun 1.3.13 and later abort where 1.3.12 returns a result, when a WTF::Vector whose element is wider than a byte needs more than 2^31 - 1 bytes: panic(main thread): abort() called, exit 134, also inside try/catch. Five scripts are in Notes. One is require("node:url").fileURLToPath("file:///%E4%B8%80" + "q".repeat(2 ** 30 - 1)), which ends in StringImpl::create (StringImpl.cpp:289).
  • WebKit 310668@main took the high bit of Vector's element count for a borrow bit, but isValidCapacityForVector (Vector.h:212) halved the limit on the size in bytes. A Vector<char16_t> went from 2^31 - 1 to 2^30 - 1 elements.

Fix

Background

  • isValidCapacityForVector<T>(n) guards each Vector buffer allocation. The crashing path calls CRASH().
  • String::fromUTF8 and other converters size a Vector<char16_t> by the length of their input, so this limit decides how long a string they accept.
  • Bun links a prebuilt WebKit named in scripts/build/deps/webkit.ts. A WebKit pull request publishes a preview build as autobuild-preview-pr-<n>-<sha8>.
Notes

Origin. A fuzzing run found the aborts one by one. No user reported them. 310668@main is "Support CanBorrow in Vector" (webkit.org/b/311221, 2026-04-06). Its message says that the maximum capacity is now 2^31 - 1, which is the count. The formula it changed limits the bytes.

Regression table. Linux x64 release builds. "this PR" is a release build of this branch.

Script 1.3.12 1.3.13 main this PR
url.fileURLToPath("file:///%E4%B8%80" + "q".repeat(2 ** 30 - 1)).length 1073741825 abort abort 1073741825
("\ud800" + "q".repeat(2 ** 30)).toWellFormed().length 1073741825 abort abort 1073741825
for (let i = 0; i < 33554431; i++) queueMicrotask(f) runs abort abort runs
new URLSearchParams("a=" + "\u4e00".repeat(2 ** 29)).get("a").length 536870912 abort abort 536870912
u = new URL("http://a/"); u.host = "q".repeat(2 ** 30); u.host.length 1073741824 abort abort 1073741824
console.count("q".repeat(2 ** 30)) prints abort abort abort
buffer.transcode(new Uint8Array(2 ** 30), "latin1", "ucs2") not implemented not implemented abort abort

The two rows that stay. Both need a Vector of bytes with 2^31 elements. The borrow bit leaves 31 bits for the count, so 2^31 - 1 is the limit for a one-byte element and no formula gives that back. console.count converts through StringImpl::tryGetUTF8ForCharacters, which asks for two bytes for each Latin-1 character (#42868). transcode grows its result in NodeBufferModule.cpp:220 (#42875).

Debug ASAN build with the pin. The queueMicrotask script runs in 215 s and the toWellFormed script in 12 s, both with exit 0 and nothing on stderr. The other three take several minutes each there and I did not run them.

The test. It runs the first script in a child and expects the length, the first five characters and the last two. It takes 8.3 s and the child peaks at 7 GiB, so it needs 12 GiB and has a 60 s timeout. A debug build takes about 7 minutes to parse a URL of that size, so debug and ASAN builds skip it. VectorSizeLimit.h is the check that every build runs: its two static_asserts fail to compile if the WebKit formula and Bun's copy differ. For the same reason this branch does not compile with src/ from main: the old static_asserts reject the new formula.

Suites. bun bd test with the pin: fileUrl.test.js, wrapAnsi.test.ts, streams-string-limit.test.ts, url-fileurltopath.test.js, url.test.ts (307 pass, 1 skip, 0 fail). Release build with the pin: the same plus streams.test.js. These are the users of maxVectorSize and maxDequeSize.

Other open pull requests.


no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/bun/util/fileUrl.test.js

@robobun

robobun commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 3:42 AM PT - Sep 17th, 2026

✅ @robobun, your commit ab0a5e225a5b4ca8fb2e9ccf9c1ec7e4afee8a9d passed in Build #116972! 🎉


🧪   To try this PR locally:

bunx bun-pr 42982

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

bun-42982 --bun

@robobun

robobun commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: reproduced on a release build of main (c6b7fcb5b, linux x64), on Bun 1.3.13, and on the 1.4.3 canary (a8e4e9042, Windows x64) with

require("node:url").fileURLToPath("file:///%E4%B8%80" + "q".repeat(2 ** 30 - 1));

The process exits 134 with panic(main thread): abort() called. The stack ends in StringImpl::create (StringImpl.cpp:289), from String::fromUTF8, from URL::fileSystemPath(). Bun 1.3.12 returns the 1073741825-character path, so this is a regression in 1.3.13. The cause is WebKit 310668@main, which halved the capacity of every Vector whose element is wider than a byte.

The engine fix is oven-sh/WebKit#691. This PR pins its preview build, updates VectorSizeLimit.h, and adds a test to test/js/bun/util/fileUrl.test.js. On a release build of main the test fails (the child exits 134). On a release build of this branch it passes in 8.3 s, and the five scripts in the description give the same results as Bun 1.3.12.

This PR is a draft until oven-sh/WebKit#691 merges. Then the pin moves to the autobuild-<sha> of the merge commit.

…de no longer aborts the process

String::fromUTF8 sized its UTF-16 buffer with a Vector constructor that calls
CRASH() past 2^30 - 1 code units. WTF::URL::fileSystemPath() decodes the path
of a file: URL through it, so fileURLToPath(), the fs functions that take a
URL, import(), require(), new Worker() and process.dlopen() aborted on a
decoded path of 2^30 bytes that is not all ASCII.

The preview build makes the conversion return a null string, which these
callers already get for a path that is not UTF-8.
…ity from before WebKit 310668@main

The abort is a regression in Bun 1.3.13. WebKit 310668@main took the high bit
of Vector's element count for a borrow bit, but halved the limit on the size
in bytes, so every Vector whose element is wider than a byte lost half of its
capacity. oven-sh/WebKit#691 limits the count instead. fileURLToPath() returns
the 2^30 byte path again, as Bun 1.3.12 does, and the test now expects that
path and not "".

VectorSizeLimit.h states the WebKit formula in two static_asserts, so it moves
with the pin.
@robobun

robobun commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator Author

Reworked in ab0a5e2: this PR moved from oven-sh/WebKit#683 to oven-sh/WebKit#691.

oven-sh/WebKit#683 made String::fromUTF8 return a null string, so fileURLToPath returned "" for the script in the description. The abort turned out to be a regression in Bun 1.3.13 from one line of WebKit 310668@main, and oven-sh/WebKit#691 fixes that line. fileURLToPath returns the correct path again, as Bun 1.3.12 does. The description and the status comment describe the PR as it stands now.

@robobun
robobun force-pushed the robobun/364a952c/fromutf8-null-buffer branch from 1b59332 to ab0a5e2 Compare September 17, 2026 10:15
@robobun robobun changed the title Bump WebKit (oven-sh/WebKit#683 preview): a file URL too long to decode no longer aborts the process Bump WebKit (oven-sh/WebKit#691 preview): restore the Vector capacity that WebKit 310668@main halved Sep 17, 2026

This branch has not been deployed

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant