Repository navigation
Conversation
NDK r27c ships a libc++ from an unreleased LLVM snapshot. Its std::expected stores has_val after the union. Every libc++ from LLVM 18.1 on, and every NDK from r28 on, stores it in the union's tail padding when the value type has any. Bun decodes std::expected<ParseInnerResult, String> from the prebuilt JavaScriptCore inline on every module parse, so Bun's Android objects and the prebuilt must be built with NDKs that agree on libc++'s layout. At Bun 1.4.4's pin the two layouts differed (has_val at 0xE8 against 0xE2), which is what a Bun built with NDK r30 against the r27c prebuilt hit. The pin moves together with NDK_VERSION in oven-sh/WebKit's Dockerfile.android and with WEBKIT_VERSION. The note next to WEBKIT_VERSION, the upgrade checklist and the NDK hints in config.ts now say so.
Collaborator
Author
|
Updated 3:38 PM PT - Oct 23rd, 2026
✅ @robobun, your commit f12efcca49882630627600ae6bdb70b095d2d009 passed in 🧪 To try this PR locally: bunx bun-pr 46623That installs a local version of the PR into your bun-46623 --bun |
This was referenced Oct 23, 2026
This branch has not been deployed
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.
Fixes #46595
Problem
scripts/build/ci-images/spec.ts,pins.androidNdk). The Android prebuilt of JavaScriptCore is built with the same r27c in oven-sh/WebKit'sDockerfile.android.std::expectedstoreshas_valafter the union. Every libc++ from LLVM 18.1 on, and every NDK from r28 on, stores it in the value type's tail padding when there is any. Bun decodesstd::expected<ParseInnerResult, String>from the prebuilt inline on every module parse (Parser.h, viaBunAnalyzeTranspiledModule.cpp:257).d6375c72)ParseInnerResultends in auint16_t, sohas_valsits at 0xE8 under r27c and 0xE2 under r30. A Bun built with r30 against that prebuilt crashes. Termux builds with r30 and carries a patchedexpected.hplus a sed onscripts/build/flags.ts.Fix
pins.androidNdkmoves to r30 with the sha256 ofandroid-ndk-r30-linux.zip. Google publishes only the SHA-1 (5107f898313790e449e87eee2183d9a20602dee9). The CI image bake checks the sha256.Dockerfile.androidmoves to the same r30.WTF/Atomics.hdrops thestd::atomic_reffallback that Upgrade to upstream WebKit 33ce3bf11a71 WebKit#860 added for r27c. Its author named a newer NDK as the other way. The file is upstream's again.WEBKIT_VERSIONindeps/webkit.ts, next topins.androidNdk, and in the upgrade checklist. The two NDK hints inconfig.tsname the pinned release and its download.bun run ci:imagesrenames onlylinux-aarch64-debian(the Android build host), so the PR build bakes it.test/internal/source-lints/{ci-images,ci-image-pins,webkit-prebuilt-url}.test.tspass.tsconscripts/buildpasses.Background
androidNdk()inspec.tsandlinkNdkRuntimesIntoClang()inconfig.tssymlink the NDK's runtimes into the host clang's resource dir.Dockerfile.androiddoes the same symlinks and test-links an Android executable, so the fork's image build proves r30 keeps that layout.5e3554face)ParseInnerResultgained a trailingunsigned, so this one type has no tail padding and the same layout under both libc++ versions. The class remains: 64std::expecteddeclarations in the prebuilt headers, and the next upstream edit toParseInnerResultreopens it. The pin bump removes the class. Both Android lanes are build-only, so CI cannot observe a mismatch.--webkit=local. Considered out-of-lineParserinstantiations in the fork: they protect one of 64 declarations.Downsides
WEBKIT_VERSIONpulls every fork change between5e3554faceand that build into the same change. Binary size and symbol deltas get measured once the build exists.Notes
Why the bump is one-time. LLVM history of
libcxx/include/__expected/expected.h: commit134c915955(2023-10-30, llvm #68733) movedhas_valout of the union's tail padding. Commit4f4690530e(2024-01-22, llvm #69673) added__fits_in_tail_paddingand moved it back. NDK r27's clang-r522817 is an LLVM merge dated 2023-12-29, between those two commits.llvmorg-18.1.0has__fits_in_tail_padding. NDK r28 (clang-r530567c), r29 (clang-r563880c), r30 (clang-r574158c) and Bun's pinned host clang 23.1.1 all share the final layout.The offsets.
ParseInnerResultatd6375c72: two pointers,FunctionStack(16), twoVariableEnvironment(96 each),CodeFeatures(uint16_tat 224), 6 bytes of tail padding, size 232.has_valat 232 (0xE8) in the r27c layout, at 226 (0xE2) in the tail padding with LLVM 18.1+. At5e3554facethe struct addsunsigned usedPrivateNameCountat 228: size 232, no tail padding,has_valat 232 in both.The sha256. This container has no route to dl.google.com. The value is the one
termux/termux-packagesscripts/setup-android-sdk.shuses forandroid-ndk-r30-linux.zip. Both the oven-sh/WebKit image build (sha256sum -c) and the CI image bake (downloadwithsha256) fail if it is wrong.What renames.
bun run ci:imagesbefore and after:linux-aarch64-debian-a8bf3197baf56377becomeslinux-aarch64-debian-a26465ce83461917.linux-x64-debiankeeps its name.Old pin copies.
git grepforr27cand the old sha256 finds no other copy in this repo.Self-review: 14 concerns raised, 12 addressed. Two left as notes: a compile-time
static_asserton the prebuilt's_LIBCPP_VERSION(a define emitted byDockerfile.androidintocmakeconfig.h) would catch a future mismatch at build time, andpins.freebsd(14.4) differs from the fork'sDockerfile.freebsd(14.3). Both are separate changes.Layout check once the build exists.
llvm-dwarfdump --debug-infoon the Android debug lane'slibJavaScriptCore.aand on Bun's object forBunAnalyzeTranspiledModule.cpp: compare the__has_val_member offset ofstd::expected<JSC::ParseInnerResult, WTF::String>.