From 8b31a3bc18b8478e17f30b4d50cc16a6002c8361 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 16 Jul 2026 08:26:34 +0000 Subject: [PATCH 1/2] parser: make stack-overflow failure sticky across save-point backtracking When the recursion limit fires in parseAssignmentExpression for a deeply nested object or array literal, each enclosing level retries the input as a destructuring pattern (parseAssignmentExpression) and again as a member expression (parseAssignmentElement). Both retry paths call restoreSavePoint, which clears m_errorMessage, so the stack check has to fire again at the next recursion entry. With two retry branches at every level the work becomes exponential in nesting depth, and the parser appears to hang with unbounded memory growth instead of surfacing the RangeError. m_hasStackOverflow already survives restoreSavePoint; this change makes failIfStackOverflow() consult it so the first overflow short-circuits every subsequent recursion entry and the failure propagates in O(depth). --- Source/JavaScriptCore/parser/Parser.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp index a71bce8e4589..5d366c0ce7e1 100644 --- a/Source/JavaScriptCore/parser/Parser.cpp +++ b/Source/JavaScriptCore/parser/Parser.cpp @@ -53,7 +53,10 @@ #define consumeOrFail(tokenType, ...) do { if (!consume(tokenType)) [[unlikely]] { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) #define consumeOrFailWithFlags(tokenType, flags, ...) do { if (!consume(tokenType, flags)) [[unlikely]] { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) #define matchOrFail(tokenType, ...) do { if (!match(tokenType)) [[unlikely]] { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) -#define failIfStackOverflow() do { if (!canRecurse()) [[unlikely]] failWithStackOverflow(); } while (0) +// Once the recursion limit is hit, treat it as sticky: save-point backtracking can clear +// m_errorMessage, and retrying an alternate production (e.g. object literal -> destructuring +// pattern) at each nesting level would otherwise turn a linear failure into an exponential one. +#define failIfStackOverflow() do { if (m_hasStackOverflow || !canRecurse()) [[unlikely]] failWithStackOverflow(); } while (0) #define semanticFail(...) do { internalFailWithMessage(false, __VA_ARGS__); } while (0) #define semanticFailIfTrue(cond, ...) do { if ((cond)) [[unlikely]] internalFailWithMessage(false, __VA_ARGS__); } while (0) #define semanticFailIfFalse(cond, ...) do { if (!(cond)) [[unlikely]] internalFailWithMessage(false, __VA_ARGS__); } while (0) From 3946a08b9b73193c38cf39b0990118f56ae8dd63 Mon Sep 17 00:00:00 2001 From: robobun <117481402+robobun@users.noreply.github.com> Date: Thu, 16 Jul 2026 09:00:23 +0000 Subject: [PATCH 2/2] CI: fall back to ubuntu-ports mirror and disable fail-fast on Linux matrix ports.ubuntu.com has been unreachable for hours, and a single arm64 apt failure was cancelling all 12 Linux variants. Retry apt with a Launchpad-registered mirror on failure, and let the remaining matrix entries finish when one variant dies. Mirrors the same hardening already on the dylan/llvm-22 branch. --- .github/workflows/build-reusable.yml | 10 ++++++++++ Dockerfile | 30 ++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-reusable.yml b/.github/workflows/build-reusable.yml index 1c71527296e0..e87041bb28fa 100644 --- a/.github/workflows/build-reusable.yml +++ b/.github/workflows/build-reusable.yml @@ -32,6 +32,8 @@ jobs: name: Linux runs-on: ${{matrix.os}} strategy: + # One variant's failure shouldn't cancel the others. + fail-fast: false matrix: include: - lto_flag: "" @@ -344,6 +346,8 @@ jobs: name: Linux musl runs-on: ${{matrix.os}} strategy: + # One variant's failure shouldn't cancel the others. + fail-fast: false matrix: include: - lto_flag: "" @@ -445,6 +449,8 @@ jobs: # mac-release.bash remains for building on a real Mac locally. runs-on: linux-x64-gh strategy: + # One variant's failure shouldn't cancel the others. + fail-fast: false matrix: include: - label: bun-webkit-macos-arm64 @@ -539,6 +545,8 @@ jobs: # so all FreeBSD targets build on x64 regardless of target arch. runs-on: linux-x64-gh strategy: + # One variant's failure shouldn't cancel the others. + fail-fast: false matrix: include: - label: bun-webkit-freebsd-amd64 @@ -596,6 +604,8 @@ jobs: # cross-compile from x64 regardless of target arch. runs-on: linux-x64-gh strategy: + # One variant's failure shouldn't cancel the others. + fail-fast: false matrix: include: - label: bun-webkit-linux-arm64-android diff --git a/Dockerfile b/Dockerfile index 2d57157dc9a0..16c33406eaf9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,15 +31,20 @@ ENV DEBIAN_FRONTEND=noninteractive # Both archive.ubuntu.com and azure.archive.ubuntu.com have intermittently # timed out from inside the GitHub-hosted docker-buildx network at different -# times. Prefer Azure (faster on Azure-hosted runners) but fall back to the -# canonical mirror if `apt-get update` can't reach it. arm64 uses -# ports.ubuntu.com which has been reachable, so leave it alone. -RUN sed -i 's|http://archive.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' /etc/apt/sources.list +# times, and ports.ubuntu.com (arm64) has gone fully dark for hours at a +# stretch. Prefer Azure on amd64 (faster on Azure-hosted runners). On any +# failed attempt, swap to a fallback mirror before retrying: amd64 falls back +# to the canonical archive, arm64 falls back to a Launchpad-registered +# ubuntu-ports mirror. +RUN sed -i 's|http://archive.ubuntu.com/ubuntu|http://azure.archive.ubuntu.com/ubuntu|g' /etc/apt/sources.list \ + && echo 'Acquire::Retries "5";' > /etc/apt/apt.conf.d/99-retries -# Install basic build dependencies -RUN ( apt-get update || \ - ( sed -i 's|http://azure.archive.ubuntu.com/ubuntu|http://archive.ubuntu.com/ubuntu|g' /etc/apt/sources.list && apt-get update ) \ - ) && apt-get install -y \ +# Install basic build dependencies. `apt-get update` exits 0 on partial index +# fetch failure (only W:, not E:), which then makes the install fail with +# "no installation candidate"; retry the whole update+install, swapping to a +# fallback mirror after the first failure. +RUN for attempt in 1 2 3; do \ + apt-get update && apt-get install -y \ wget \ curl \ git \ @@ -52,6 +57,15 @@ RUN ( apt-get update || \ ca-certificates \ gnupg \ lsb-release \ + && break || { \ + echo "apt attempt $attempt failed, swapping mirrors and retrying"; \ + sed -i -e 's|http://azure.archive.ubuntu.com/ubuntu|http://archive.ubuntu.com/ubuntu|g' \ + -e 's|http://ports.ubuntu.com/ubuntu-ports|http://mirrors.ocf.berkeley.edu/ubuntu-ports|g' \ + /etc/apt/sources.list; \ + sleep 15; \ + }; \ + done \ + && dpkg -l wget curl git python3 ninja-build lsb-release >/dev/null \ && rm -rf /var/lib/apt/lists/* # Install zstd (for icu/compress-data.ts). Pinned: focal's apt has 1.4.4 which