Skip to content

Add bun.sys.ucontext_t with bionic-correct layout on x86_64 Android#30393

Open
robobun wants to merge 5 commits into
mainfrom
farm/1079a371/android-x64-ucontext
Open

Add bun.sys.ucontext_t with bionic-correct layout on x86_64 Android#30393
robobun wants to merge 5 commits into
mainfrom
farm/1079a371/android-x64-ucontext

Conversation

@robobun

@robobun robobun commented May 8, 2026

Copy link
Copy Markdown
Collaborator

Problem

std.c.ucontext_t on .linux forwards to std.os.linux.<arch>.ucontext_t, which is the glibc/musl layout: {flags, link, stack, mcontext, sigmask[128B], fpregs_mem[512B]}. bionic x86_64's ucontext_t (<sys/ucontext.h>) puts only a bare union { sigset_t; sigset64_t; } — one c_ulong, 8 bytes — between uc_mcontext and __fpregs_mem, so __fpregs_mem starts 120 bytes earlier than the Zig stdlib expects.

aarch64 is accidentally correct: bionic explicitly pads uc_sigmask back to 128 bytes there (char __padding[128 - sizeof(sigset_t)]).

No current breakagehandleSegfaultPosix takes the ucontext arg as ?*const anyopaque and never dereferences it. This is proactive: if the crash handler ever starts reading register state from the saved context (e.g. uc_mcontext.gregs[REG_RIP] / REG_RSP instead of the live siginfo), x86_64 Android would read the wrong offsets.

Fix

Same pattern as #30389 (on which this is now based):

  • src/sys/sys.zig: add pub const ucontext_t — on x86_64 Android, an extern struct matching bionic <sys/ucontext.h> (__x86_64__), with comptime offset assertions (uc_mcontext @40, uc_sigmask @296, __fpregs_mem @304, sizeof == 816) and a tripwire that fires when std.c.ucontext_t shrinks to the bionic size so the workaround can be dropped. Everywhere else it's a transparent alias of std.posix.ucontext_t. The sigmask field reuses bun.sys.sigset_t.
  • src/crash_handler/crash_handler.zig: handleSegfaultPosix's third parameter is now ?*const bun.sys.ucontext_t (still unused, but correctly typed for future use). @ptrCast at the one assignment site since Sigaction.sigaction_fn types the slot as ?*anyopaque — same C ABI.
  • test/internal/ucontext-layout.test.ts: pins @sizeOf / @offsetOf(bun.sys.ucontext_t, …) to the host-libc values on Linux x86_64 (glibc/musl on CI, bionic when run on device).

src/test_runner/harness/recover.zig also references std.c.ucontext_t, but that's a separate problem (bionic has no setcontext/getcontext at all — it would need the setjmp/longjmp path like musl) and that file is currently unreferenced.

Verification

$ zig build check-android -Dandroid_ndk_sysroot=/opt/android-ndk/…/sysroot --summary all
check-android success
  compile obj bun-debug Debug x86_64-linux-android  success
  compile obj bun-debug Debug aarch64-linux-android success
  compile obj bun ReleaseFast x86_64-linux-android  success
  compile obj bun ReleaseFast aarch64-linux-android success

$ bun bd test test/internal/ucontext-layout.test.ts
(pass) bun.sys.ucontext_t matches host libc on Linux x86_64
  → {sizeof:936, mcontext:40, sigmask:296, fpregs_mem:424, android:false}

bun run zig:check-all passes all 16 targets. Intentionally breaking an offset assertion (@sizeOf == 817) correctly fails the x86_64-android compile.

No Android runtime test is included — the misbehaviour only surfaces when the kernel fills the structure on a real x86_64 Android device, which CI does not run, and nothing in Bun currently dereferences it.

@robobun

robobun commented May 8, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 2:59 AM PT - May 8th, 2026

@robobun, your commit 72aba59 has 1 failures in Build #52781 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 30393

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

bun-30393 --bun

@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Rate limit exceeded

@robobun has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 31 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 67b944b8-33d8-4076-b8dd-92cc59644ff7

📥 Commits

Reviewing files that changed from the base of the PR and between 65cded8 and 72aba59.

📒 Files selected for processing (1)
  • test/internal/ucontext-layout.test.ts

Walkthrough

This PR adds Android x86_64–specific ucontext_t type definition matching bionic ABI layout, updates the POSIX signal handler to use typed context pointers, and exposes layout metadata via testing APIs with validation tests.

Changes

Android x86_64 ucontext_t Implementation

Layer / File(s) Summary
Type Definition (Data Contract)
src/sys/sys.zig
Defines bun.sys.ucontext_t for Android x86_64 as an extern struct matching bionic layout, with compile-time assertions validating field offsets and total size.
Signal Handler Implementation
src/crash_handler/crash_handler.zig
Updates handleSegfaultPosix callback parameter from ?*const anyopaque to ?*const bun.sys.ucontext_t and casts the handler to sigaction_fn during registration.
Testing API (JSC)
src/sys_jsc/error_jsc.zig
Adds TestingAPIs.ucontextLayout that extracts and returns bun.sys.ucontext_t size, field offsets (mcontext, sigmask, fpregs_mem), and an android platform flag; returns js_undefined on non–Linux x86_64.
JS Testing Binding
src/js/internal-for-testing.ts
Exports ucontextLayout() function that calls native TestingAPIs.ucontextLayout and returns optional layout metadata object with sizes, offsets, and android indicator.
Tests
test/internal/ucontext-layout.test.ts
Linux x86_64–only test that invokes ucontextLayout() and asserts returned layout matches expected values, with distinct assertions for Android bionic vs glibc/musl offsets and sizes.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: adding a bionic-correct ucontext_t type for x86_64 Android, which is the primary objective of the PR.
Description check ✅ Passed The PR description comprehensively addresses both required template sections: 'What does this PR do?' explains the problem, fix, and implementation details; 'How did you verify your code works?' provides build commands and test results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

robobun added 2 commits May 8, 2026 08:18
std.c.ucontext_t on .linux forwards to the glibc/musl layout with a
128-byte sigmask between uc_mcontext and fpregs_mem. bionic x86_64
puts a bare c_ulong (8 bytes) there instead, so __fpregs_mem starts
120 bytes earlier than the Zig stdlib expects. aarch64 is
accidentally correct because bionic pads uc_sigmask back to 128
bytes on that arch.

Nothing dereferences the signal handler's ucontext_t* today, but
handleSegfaultPosix now takes ?*const bun.sys.ucontext_t so that if
the crash handler ever reads register state from the saved context
it does so from the correct offsets on x86_64 Android.

Also adds zig build check-android[-debug], gated on
-Dandroid_ndk_sysroot like check-freebsd, so the Android-only struct
gets compile-checked with its comptime offset tripwire.
Exposes @sizeof / @offsetof for bun.sys.ucontext_t on Linux x86_64 and
pins the host-libc layout (glibc/musl on CI, bionic on device).
@robobun robobun force-pushed the farm/1079a371/android-x64-ucontext branch from ead1da0 to 291dca8 Compare May 8, 2026 08:25
Comment thread test/internal/ucontext-layout.test.ts Outdated
Bun reports process.platform === "android" on bionic, not "linux",
so the isLinux gate from harness skipped the test there and the
bionic-offset branch was unreachable.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/internal/ucontext-layout.test.ts`:
- Around line 29-35: The test currently derives the expected branch from the
value under test (layout!.android) which can hide regressions; change the
selection of the expected object to use the independent isAndroid flag (e.g.,
use isAndroid ? {...android:true} : {...android:false}) instead of
layout!.android, and add an explicit assertion that layout.android equals
isAndroid so the test fails if the reported platform differs from the external
isAndroid signal; update references to the expected object creation (the const
expected) and ensure you still assert other fields against layout.mcontext,
layout.sigmask, layout.fpregs_mem, and layout.sizeof as before.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fc5dd953-e7d0-489e-ac68-830d1a3af3b8

📥 Commits

Reviewing files that changed from the base of the PR and between 31afc0d and 65cded8.

📒 Files selected for processing (1)
  • test/internal/ucontext-layout.test.ts

Comment thread test/internal/ucontext-layout.test.ts Outdated
….android

Deriving the expected values from the value under test would mask
a regression where Zig-side Environment.isAndroid disagreed with
the runtime platform.
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.

1 participant