-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Upgrade WebKit to 456cd04b8d5be123bd451f2c007b97dbb3ffed57 #29161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
2650be5
67a210f
4776017
0293909
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -673,7 +673,7 @@ extern "C" void JSBundlerPlugin__drainDeferred(Bun::JSBundlerPlugin* pluginObjec | |
| auto& vm = pluginObject->vm(); | ||
| auto scope = DECLARE_THROW_SCOPE(vm); | ||
| for (auto promiseValue : arguments) { | ||
| JSPromise* promise = jsCast<JSPromise*>(JSValue::decode(promiseValue)); | ||
| JSPromise* promise = jsCast<JSPromise*>(promiseValue); | ||
| if (rejected) { | ||
| promise->reject(vm, globalObject, JSC::jsUndefined()); | ||
| } else { | ||
|
Comment on lines
673
to
679
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟣 Pre-existing bug: Extended reasoning...What the bug is: How it manifests in watch mode: Each build cycle, Why existing code doesn't prevent it: The Secondary breakage — GC overhead: The Concrete proof — step by step:
How to fix: Add Relation to this PR: This PR directly modifies |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -494,31 +494,31 @@ | |
| } else { | ||
| auto headers = createHeaders(globalObject); | ||
| RETURN_IF_EXCEPTION(scope, -1); | ||
| args.set(A_HEADERS, headers); | ||
| args.at(A_HEADERS) = headers; | ||
| if (m_parserData.type == HTTP_REQUEST) { | ||
| args.set(A_URL, m_url.toString(globalObject)); | ||
| args.at(A_URL) = m_url.toString(globalObject); | ||
| } | ||
| } | ||
|
|
||
| m_numFields = 0; | ||
| m_numValues = 0; | ||
|
|
||
| if (m_parserData.type == HTTP_REQUEST) { | ||
| args.set(A_METHOD, jsNumber(m_parserData.method)); | ||
| args.at(A_METHOD) = jsNumber(m_parserData.method); | ||
| } | ||
|
|
||
| if (m_parserData.type == HTTP_RESPONSE) { | ||
| args.set(A_STATUS_CODE, jsNumber(m_parserData.status_code)); | ||
| args.set(A_STATUS_MESSAGE, m_statusMessage.toString(globalObject)); | ||
| args.at(A_STATUS_CODE) = jsNumber(m_parserData.status_code); | ||
| args.at(A_STATUS_MESSAGE) = m_statusMessage.toString(globalObject); | ||
| } | ||
|
Check notice on line 513 in src/bun.js/bindings/node/http/NodeHTTPParser.cpp
|
||
|
Comment on lines
+497
to
513
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟣 Pre-existing bug: in NodeHTTPParser.cpp onHeadersComplete(), the calls m_url.toString(globalObject) (HTTP_REQUEST path) and m_statusMessage.toString(globalObject) (HTTP_RESPONSE path) lack RETURN_IF_EXCEPTION(scope, -1) guards. If either call throws on OOM while allocating a JSString, execution continues with a pending VM exception and invokes profiledCall() — violating JSC's core invariant. The fix is to add RETURN_IF_EXCEPTION(scope, -1) after each toString() call; this bug predates the PR but the PR touches these exact lines. Extended reasoning...What the bug is and how it manifests: In NodeHTTPParser.cpp, onHeadersComplete() uses DECLARE_TOP_EXCEPTION_SCOPE. Two calls — m_url.toString(globalObject) at line 499 (HTTP_REQUEST path) and m_statusMessage.toString(globalObject) at line 512 (HTTP_RESPONSE path) — are not followed by RETURN_IF_EXCEPTION. StringPtr::toString() calls JSC::jsString(vm, WTF::String::fromUTF8(...)), which allocates a JSString on the GC heap. If that allocation fails with OutOfMemory, JSC stores a pending exception in the VM and the call returns a garbage JSValue. Without a guard, execution continues: m_numFields/m_numValues are cleared, further args slots are written, and eventually JSC::profiledCall() is invoked with a pending exception still set — which is undefined behavior in JSC and triggers assertions in debug builds. The specific code path that triggers it: Under memory pressure, any GC heap allocation can fail with an OutOfMemoryError. In HTTP_REQUEST mode, args.at(A_URL) = m_url.toString(globalObject) stores a garbage value and sets a pending exception. Execution continues through m_numFields = 0 resets, the A_METHOD/A_VERSION_MAJOR/A_VERSION_MINOR/A_SHOULD_KEEP_ALIVE/A_UPGRADE assignments, and then hits JSC::profiledCall() at line 525 with a pending exception still live. Why existing code does not prevent it: The DECLARE_TOP_EXCEPTION_SCOPE does NOT automatically propagate exceptions — it only asserts in debug builds that no exception is pending at scope boundaries. Protection requires manual RETURN_IF_EXCEPTION calls. Crucially, createHeaders() — called in the same function — uses RETURN_IF_EXCEPTION after every identical toString() call (m_fields[i].toString, m_values[i].toTrimmedString), confirming the codebase treats these as throwable. The omission in onHeadersComplete is an inconsistency, not a deliberate design choice. Addressing the refutation: One verifier argued that jsString() never sets a JS exception and instead causes a hard crash on OOM. However, JSC's GC heap allocator can and does report OOM as a thrown JavaScript OutOfMemoryError — it does not always crash. The createHeaders() function in the same file guards the same toString() pattern with RETURN_IF_EXCEPTION. If jsString() truly could not throw, those guards would be harmless no-ops; their presence reflects the actual JSC semantics. The flush() function at the bottom of the file appends m_url.toString(globalObject) to args without a guard, which is the same bug. Step-by-step proof: (1) HTTP request arrives; onHeadersComplete() is called. (2) m_haveFlushed is false, so createHeaders() succeeds and args.at(A_HEADERS) is set. (3) m_parserData.type == HTTP_REQUEST, so args.at(A_URL) = m_url.toString(globalObject) executes. (4) Under OOM, jsString() fails, sets an OutOfMemoryError on the VM, and returns a garbage JSValue — no guard catches this. (5) Execution falls through: m_numFields = 0; m_numValues = 0; args.at(A_METHOD) = jsNumber(...); additional slots filled. (6) JSC::profiledCall() is invoked with a pending exception. Debug builds ASSERT; release builds have undefined behavior. How to fix it: Add RETURN_IF_EXCEPTION(scope, -1) immediately after args.at(A_URL) = m_url.toString(globalObject) (line 499) and after args.at(A_STATUS_MESSAGE) = m_statusMessage.toString(globalObject) (line 512). The flush() function also appends m_url.toString(globalObject) without a guard and should be fixed in the same pass. |
||
|
|
||
| args.set(A_VERSION_MAJOR, jsNumber(m_parserData.http_major)); | ||
| args.set(A_VERSION_MINOR, jsNumber(m_parserData.http_minor)); | ||
| args.at(A_VERSION_MAJOR) = jsNumber(m_parserData.http_major); | ||
| args.at(A_VERSION_MINOR) = jsNumber(m_parserData.http_minor); | ||
|
|
||
| bool shouldKeepAlive = llhttp_should_keep_alive(&m_parserData); | ||
|
|
||
| args.set(A_SHOULD_KEEP_ALIVE, jsBoolean(shouldKeepAlive)); | ||
| args.set(A_UPGRADE, jsBoolean(m_parserData.upgrade)); | ||
| args.at(A_SHOULD_KEEP_ALIVE) = jsBoolean(shouldKeepAlive); | ||
| args.at(A_UPGRADE) = jsBoolean(m_parserData.upgrade); | ||
|
|
||
| CallData callData = getCallData(onHeadersCompleteCallback); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: oven-sh/bun
Length of output: 1411
Remove or rebuild WebKit release with complete LTO assets.
Release
autobuild-42f80a684c5df57121a97e20825a3bcab7a0741bexists but is missing:bun-webkit-windows-amd64-lto.tar.gzbun-webkit-macos-arm64-lto.tar.gzThese prebuilt assets are required for LTO builds on Windows and macOS. Rebuild the release with all LTO variants or revert to a prior version with complete assets.
🤖 Prompt for AI Agents