Skip to content

FreeList::forEach: bound the interval assert by MarkedBlock::blockSize - #247

Merged
Jarred-Sumner merged 1 commit into
mainfrom
fix/freelist-foreach-interval-assert-linux-arm64
Jun 2, 2026
Merged

FreeList::forEach: bound the interval assert by MarkedBlock::blockSize#247
Jarred-Sumner merged 1 commit into
mainfrom
fix/freelist-foreach-interval-assert-linux-arm64

Conversation

@robobun

@robobun robobun commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Problem

FreeList::forEach asserts that a free-list interval is smaller than a hardcoded 16 KB:

ASSERT(intervalEnd - intervalStart < (ptrdiff_t)(16 * KB));

But the real invariant is "an interval never spans more than one MarkedBlock payload", and MarkedBlock::blockSize is std::max(16 * KB, CeilingOnPageSize) — which is 64 KB on Linux ARM64 (PageBlock.h: the page size there is unknowable at compile time; e.g. RHEL uses 64 KiB pages). On that platform, specializedSweep of an empty block creates a single interval spanning the whole ~63 KB payload, so the assert fires at the first MarkedBlock::Handle::stopAllocating in any ASSERT_ENABLED build:

ASSERTION FAILED: intervalEnd - intervalStart < (ptrdiff_t)(16 * KB)
JavaScriptCore/PrivateHeaders/JavaScriptCore/FreeListInlines.h(63) : void JSC::FreeList::forEach(const Func &) const [Func = (lambda at Source/JavaScriptCore/heap/MarkedBlock.cpp:231:9)]

This makes every assert-enabled linux-arm64 artifact from this repo (-debug, -debug-asan, -asan) crash as soon as it runs JavaScript that triggers a GC stop. It went unnoticed because nothing consumed those artifacts until now: oven-sh/bun#31699 adds a linux-aarch64 ASAN lane to Bun's CI, and its first run died on exactly this assertion while generating features.json (build: https://buildkite.com/bun/bun/builds/59814). macOS arm64 is unaffected (Darwin's CeilingOnPageSize is 16 KB), as is linux x64 (4 KB pages → 16 KB blocks, payload < 16 KB so the assert could mathematically never fire).

Fix

Bound the assert by MarkedBlock::blockSize (already in scope — FreeListInlines.h includes MarkedBlock.h). On every platform where blockSize is 16 KB this compiles to the identical check; on linux-arm64 it becomes the correct 64 KB bound.

The same stale bound exists in upstream WebKit (Source/JavaScriptCore/heap/FreeListInlines.h:63), so this is a candidate to carry upstream on the next rebase.

Verification

Analysis path: PageBlock.h CeilingOnPageSize = 64 * KB for OS(LINUX) && CPU(ARM64)MarkedBlock.h blockSize = std::max(16 * KB, CeilingOnPageSize)MarkedBlockInlines.h specializedSweep builds one interval of payloadEnd - payloadBegin (bounded by payloadSize < blockSize) → MarkedBlock.cpp:231 freeList.forEach hits the assert. Once an autobuild release exists, Bun's PR-only linux-aarch64 ASAN lane (oven-sh/bun#31699) will exercise the -asan arm64 artifact end-to-end against Bun's full test suite.

The assert hardcoded 16 KB, but MarkedBlock::blockSize is
max(16 KB, CeilingOnPageSize), which is 64 KB on Linux ARM64
(PageBlock.h: the page size there is unknowable at compile time, e.g.
RHEL uses 64 KiB pages). On that platform a freshly swept empty block
has a single free interval spanning the whole ~63 KB payload, so any
ASSERT_ENABLED build (debug, debug-asan, asan) fails at the first
MarkedBlock::Handle::stopAllocating:

  ASSERTION FAILED: intervalEnd - intervalStart < (ptrdiff_t)(16 * KB)
  JavaScriptCore/heap/FreeListInlines.h(63)

On every platform where blockSize is 16 KB the check is unchanged.
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@robobun, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 21 minutes and 24 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 090db6b7-a60b-4536-960a-cf5f7948a6f6

📥 Commits

Reviewing files that changed from the base of the PR and between c591a18 and 522699c.

📒 Files selected for processing (1)
  • Source/JavaScriptCore/heap/FreeListInlines.h

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

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Preview Builds

Commit Release Date
522699c6 autobuild-preview-pr-247-522699c6 2026-06-02 05:28:14 UTC

@Jarred-Sumner
Jarred-Sumner merged commit f18cf9c into main Jun 2, 2026
47 checks passed
robobun added a commit to oven-sh/bun that referenced this pull request Jun 2, 2026
Picks up oven-sh/WebKit#247: FreeList::forEach asserted a hardcoded
16 KB interval bound, but MarkedBlock::blockSize is 64 KB on Linux
ARM64 (CeilingOnPageSize), so every ASSERT_ENABLED arm64-linux
artifact (-asan, -debug, -debug-asan) crashed at the first GC stop.
The new linux-aarch64-asan lane needs the fixed -asan prebuilt.

Also picks up from oven-sh/WebKit main: xwin 0.9.0, UB fix in
double-to-int conversions, JIT disassembler compiled out of release,
windows amd64-baseline ThinLTO variant.
Jarred-Sumner pushed a commit to oven-sh/bun that referenced this pull request Jun 2, 2026
Picks up oven-sh/WebKit#247: FreeList::forEach asserted a hardcoded
16 KB interval bound, but MarkedBlock::blockSize is 64 KB on Linux
ARM64 (CeilingOnPageSize), so every ASSERT_ENABLED arm64-linux
artifact (-asan, -debug, -debug-asan) crashed at the first GC stop.
The new linux-aarch64-asan lane needs the fixed -asan prebuilt.

Also picks up from oven-sh/WebKit main: xwin 0.9.0, UB fix in
double-to-int conversions, JIT disassembler compiled out of release,
windows amd64-baseline ThinLTO variant.
Jarred-Sumner pushed a commit to oven-sh/bun that referenced this pull request Jun 2, 2026
Bumps `WEBKIT_VERSION` from `963f8758` to
[`6d586e29`](oven-sh/WebKit@6d586e2),
the current head of oven-sh/WebKit main. The prebuilt release
[`autobuild-6d586e293f008f0e74e5697611a379b1b24815c9`](https://github.com/oven-sh/WebKit/releases/tag/autobuild-6d586e293f008f0e74e5697611a379b1b24815c9)
is published with all platform tarballs.

This range is a fast-forward of 6 fork-local commits — no upstream
WebKit merge:

-
[`27f4e7a9`](oven-sh/WebKit@27f4e7a)
Fix UB in double-to-int conversions across JSC (oven-sh/WebKit#244)
-
[`f18cf9c2`](oven-sh/WebKit@f18cf9c)
FreeList::forEach: bound the interval assert by MarkedBlock::blockSize
(oven-sh/WebKit#247)
-
[`48460d87`](oven-sh/WebKit@48460d8)
Compile out the JIT disassembler in release builds (oven-sh/WebKit#241)
-
[`6d586e29`](oven-sh/WebKit@6d586e2)
windows cross: add the bun-webkit-windows-amd64-asan variant
(oven-sh/WebKit#240)
-
[`c787a5a7`](oven-sh/WebKit@c787a5a)
windows cross: add the amd64-baseline ThinLTO variant
-
[`c591a185`](oven-sh/WebKit@c591a18)
windows: update xwin to 0.9.0 (oven-sh/WebKit#242)

Checks:

- No `Source/JavaScriptCore/runtime/JSType.h` changes in the range, so
no `src/jsc/JSType.rs` update needed.
- The workflow change (#240) only adds a new
`bun-webkit-windows-amd64-asan.tar.gz` asset; all tarball names
`prebuiltSuffix()` produces are present in the release.
liooil pushed a commit to liooil/poly that referenced this pull request Aug 7, 2026
Bumps `WEBKIT_VERSION` from `963f8758` to
[`6d586e29`](oven-sh/WebKit@6d586e2),
the current head of oven-sh/WebKit main. The prebuilt release
[`autobuild-6d586e293f008f0e74e5697611a379b1b24815c9`](https://github.com/oven-sh/WebKit/releases/tag/autobuild-6d586e293f008f0e74e5697611a379b1b24815c9)
is published with all platform tarballs.

This range is a fast-forward of 6 fork-local commits — no upstream
WebKit merge:

-
[`27f4e7a9`](oven-sh/WebKit@27f4e7a)
Fix UB in double-to-int conversions across JSC (oven-sh/WebKit#244)
-
[`f18cf9c2`](oven-sh/WebKit@f18cf9c)
FreeList::forEach: bound the interval assert by MarkedBlock::blockSize
(oven-sh/WebKit#247)
-
[`48460d87`](oven-sh/WebKit@48460d8)
Compile out the JIT disassembler in release builds (oven-sh/WebKit#241)
-
[`6d586e29`](oven-sh/WebKit@6d586e2)
windows cross: add the bun-webkit-windows-amd64-asan variant
(oven-sh/WebKit#240)
-
[`c787a5a7`](oven-sh/WebKit@c787a5a)
windows cross: add the amd64-baseline ThinLTO variant
-
[`c591a185`](oven-sh/WebKit@c591a18)
windows: update xwin to 0.9.0 (oven-sh/WebKit#242)

Checks:

- No `Source/JavaScriptCore/runtime/JSType.h` changes in the range, so
no `src/jsc/JSType.rs` update needed.
- The workflow change (#240) only adds a new
`bun-webkit-windows-amd64-asan.tar.gz` asset; all tarball names
`prebuiltSuffix()` produces are present in the release.
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.

2 participants