Skip to content

Enable bun:ffi (TinyCC) on Windows ARM64 - #33696

Merged
dylan-conway merged 7 commits into
mainfrom
claude/ffi-windows-arm64
Jul 20, 2026
Merged

Enable bun:ffi (TinyCC) on Windows ARM64#33696
dylan-conway merged 7 commits into
mainfrom
claude/ffi-windows-arm64

Conversation

@Jarred-Sumner

@Jarred-Sumner Jarred-Sumner commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Supersedes #33653 (the TinyCC upgrade; the first commit here is that PR's content) and #29476. Enables bun:ffi on Windows ARM64: drops the windows-arm64 exclusion from cfg.tinycc, the generated ENABLE_TINYCC constant, and the tcc_sys link stubs, un-skips the FFI tests that were gated on the platform, and bumps the TinyCC pin to oven-sh/tinycc@05f0fafa (which is 8a6cbc12 plus oven-sh/tinycc#3).

The windows-arm64 bug this uncovered (root-caused and fixed in the TinyCC fork)

Enabling the platform made the windows-11-aarch64 CI lane run the FFI suites on real hardware for the first time, which exposed wrong doubles (sum(0.5…9.5) = 46 instead of 50) and segfaults in every JSCallback test. Root cause, proven with an in-CI probe that dumped the JIT machine code from the runner:

TinyCC's arm64 backend decides whether a 64-bit constant fits an ADD/SUB immediate with !(val & ~0xffful). On an LLP64 host (which is exactly how Bun builds TinyCC into bun.exe on Windows via clang-cl) unsigned long is 32 bits, so ~0xffful zero-extends to 0x00000000fffff000, and any constant with no bits in [12,32) "fits". 1ll << 49 is JSC's DoubleEncodeOffset, used by every bun:ffi trampoline, and it compiled to add xN, xN, #0:

  • machine code on the CI runner: … ldur x0,[x29,#-8]; add x0,x0,#0 …
  • same source, LP64-built tcc: … mov x30,#0x2000000000000; add x0,x0,x30 …

So every double crossing the FFI boundary lost the NaN-boxing offset (JS saw bits − 2^49: 12.25→11.25, 50→46) and pointer arguments decoded to wild addresses (the segfaults). LP64-built TinyCC (Linux/macOS) is unaffected; the fix produces byte-identical output there, which is why the bug only ever existed on Windows ARM64. Fixed in the fork (arm64_gen_opic, arm64_check_offset, arm64_sym) by using uint64_t-typed masks; TinyCC's own test suite passes, and oven-sh/tinycc#3 adds regression cases to tests2/73_arm64. This also affects any natively-built windows-arm64 TinyCC upstream.

Known parity notes (pre-existing, unchanged)

  • cc() code with a >4 KB stack frame needs __chkstk, which Bun doesn't provide on any Windows target.
  • long double soft-float helpers aren't provided on any arm64 target.

Test plan

  • Linux/macOS/Windows-x64 behavior unchanged (same suites as Update TinyCC to latest upstream #33653; LP64 tcc output byte-identical across the fix)
  • Cross-built windows-arm64 bun.exe from Linux links with TinyCC enabled
  • windows-11-aarch64 CI lane: bun:ffi suites green with the LLP64 fix (build #71302, and re-verified locally on Windows 11 ARM64 at e83d3d00)

Fixes #28055

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Found 1 issue this PR may fix:

  1. Support bun:ffi on Windows ARM64 #28055 - Directly requests enabling bun:ffi on Windows ARM64, which is exactly what this PR does

If this is helpful, copy the block below into the PR description to auto-close this issue on merge.

Fixes #28055

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. deps(tinycc): enable bun:ffi on Windows ARM64 #29476 - Also enables bun:ffi (TinyCC) on Windows ARM64 by removing the same platform exclusions from build config, tcc_sys, and test guards

🤖 Generated with Claude Code

@robobun

robobun commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator
Updated 11:34 PM PT - Jul 19th, 2026

@robobun, your commit e83d3d00209058071a0075b5e3cfc2b3e749bdc4 passed in Build #76019! 🎉


🧪   To try this PR locally:

bunx bun-pr 33696

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

bun-33696 --bun

@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

Cleaned this up so it's landable — it had drifted 3 days behind main and was still carrying the two temporary diagnostic commits, which were ~all of the red on it.

What changed (head eef6e546f5e2f906):

  • Dropped the two win-arm64-diag.test.ts commits (verified first that they touch only that file, so nothing else was lost). Their job was done: the probe's own CI output on the windows-11-aarch64 runner is the proof the fix works — every probe (q2_f64 12.25→12.25, q1_bits correct, pointer echo identical, q7_deref, q8_jscallback) returned the right value with exit 0, and the dumped JIT bytes contain the corrected mov x30,#0x2000000000000; add x0,x0,x30 where the LLP64 bug emitted add x0,x0,#0.
  • Rebased the remaining 3 commits onto current main. One real conflict (napi-value-ffi.test.ts imports). One silent semantic break the rebase could not see: main has since added another isFFIUnavailable = isWindows && isArm64 gate + a use in test/js/bun/ffi/ffi.test.js (no textual overlap with this branch's import removal, so git merged it into a ReferenceError). Folded the fix into the enablement commit, so it now un-gates all three sites in that file.
  • Swept the whole tree for any other win-arm64 FFI/TinyCC gating added to main since this branch was cut (every spelling: isArm64, windows && arm64, all(windows, target_arch=…), isFFIUnavailable): none remain outside intentionally-unrelated sites (esbuild/msgpackr prebuilt availability, the crash-handler platform tag, windows-shim). process.versions.tinycc in process.test.js already matches the new TINYCC_COMMIT (8a6cbc12).
  • Locally on this branch (Linux x64, which rebuilds TinyCC at the new pin): cc.test.ts, ffi.test.js, ffi-error-messages.test.ts, napi-value-ffi.test.ts0 fail.

The branch is now exactly: TinyCC → c22ca054, enable on Windows ARM64, TinyCC → 8a6cbc12 (the LLP64 immediate fix). Marking it ready — the fresh windows-11-aarch64-test-bun run on this head is the clean acceptance test for #28055, with no always-failing diag file muddying it. Note #29476 covers the same ground with neither TinyCC fix and should likely close in favor of this.

@Jarred-Sumner
Jarred-Sumner marked this pull request as ready for review July 10, 2026 03:19
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

TinyCC is enabled on Windows ARM64, its pinned commit and runtime TLS patch are updated, x86_64 variadic argument handling is added, and FFI tests remove Windows ARM64 exclusions while covering variadic calls and thread-local storage errors.

Changes

TinyCC platform and FFI support

Layer / File(s) Summary
Update TinyCC platform gating and dependency integration
scripts/build/buildOptionsRs.ts, scripts/build/config.ts, scripts/build/deps/tinycc.ts, scripts/build/source.ts, src/tcc_sys/tcc.rs, patches/tinycc/tccrun-shf-tls.patch
TinyCC exclusions now target Android and FreeBSD, Windows ARM64 is no longer excluded, the pinned TinyCC commit changes, and TLS rejection scans TLS-marked sections.
Implement x86_64 variadic argument handling
src/runtime/ffi/libtcc1.c
Adds guarded __va_arg handling for register, floating-point, and stack arguments with alignment and overflow support.
Expand FFI and platform test coverage
test/js/bun/ffi/*, test/js/node/fs/*, test/js/node/process/process.test.js, test/napi/napi-value-ffi.test.ts
Adds variadic, long-double, and thread-local-storage tests, updates TinyCC version expectations, and removes obsolete Windows ARM64 test skips.

Possibly related PRs

Suggested reviewers: dylan-conway

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes align with #28055 by enabling TinyCC/FFI on Windows ARM64, bumping TinyCC, and unskipping the ARM64 FFI tests.
Out of Scope Changes check ✅ Passed No clearly unrelated changes stand out; the extra TinyCC and test updates still support the Windows ARM64 FFI enablement.
Title check ✅ Passed The title clearly matches the main change: enabling bun:ffi/TinyCC on Windows ARM64.
Description check ✅ Passed It includes the PR purpose and verification/test plan, though it uses custom headings instead of the template's exact section names.

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

@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: 4

🤖 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 `@scripts/build/config.ts`:
- Around line 866-868: Confirm that the pending Windows ARM64 CI acceptance run
passes before merging the change to the tinycc default in the build
configuration; do not land the new TinyCC/FFI path until this platform-specific
validation succeeds.

In `@src/runtime/ffi/libtcc1.c`:
- Around line 608-611: Shorten the comment above the libtcc1 implementation to
no more than three lines while preserving the key context: why __va_arg is
present, that Bun replaces libtcc1, its x86_64 SysV scope, and why extern
abort() is intentionally omitted.

In `@test/js/bun/ffi/cc.test.ts`:
- Around line 618-621: The explanatory comment in the TinyCC TLS test exceeds
the three-line limit; condense it to at most three lines while retaining the key
point that Local-Exec TLS is invalid for in-memory relocation and must be
rejected to prevent corruption.
- Around line 624-626: Update the TLS fixture setup in the parameterized test to
use disposable temp directory handling: replace tempDirWithFiles() with using
and tempDir(), then create/write tls.c within that directory while preserving
the existing fixture contents and test behavior.
🪄 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: 98d027c2-2024-440e-a28e-e01d3d81b0f8

📥 Commits

Reviewing files that changed from the base of the PR and between 90f8746 and f5e2f90.

📒 Files selected for processing (14)
  • scripts/build/buildOptionsRs.ts
  • scripts/build/config.ts
  • scripts/build/deps/tinycc.ts
  • scripts/build/source.ts
  • src/runtime/ffi/libtcc1.c
  • src/tcc_sys/tcc.rs
  • test/js/bun/ffi/cc.test.ts
  • test/js/bun/ffi/ffi-error-messages.test.ts
  • test/js/bun/ffi/ffi-viewSource-non-object.test.ts
  • test/js/bun/ffi/ffi.test.js
  • test/js/node/fs/cp.test.ts
  • test/js/node/fs/fs-writeSync-stdio-windows.test.ts
  • test/js/node/process/process.test.js
  • test/napi/napi-value-ffi.test.ts
💤 Files with no reviewable changes (1)
  • scripts/build/buildOptionsRs.ts

Comment thread scripts/build/config.ts
Comment thread src/runtime/ffi/libtcc1.c Outdated
Comment thread test/js/bun/ffi/cc.test.ts Outdated
Comment thread test/js/bun/ffi/cc.test.ts Outdated
@Jarred-Sumner

Copy link
Copy Markdown
Collaborator Author

CI verdict for the cleaned head (f5e2f906), taken from the all-shards failure list rather than the check badge (the windows-11-aarch64-test-bun status reflects one of several parallel slice jobs, so a badge alone is not evidence):

  • No FFI test and no windows-aarch64 test appears anywhere in build #71302's failure list.
  • At the job-log level, test/js/bun/ffi/ffi.test.js — whose JSCallback tests previously all segfaulted on this platform — ran in its windows-11-aarch64 slice and passed.
  • The build's only failures are two unrelated Linux flakes, verified by content: test/regression/issue/26030.test.ts is a MySQL describeWithContainer test (the recurring mysql_plain container flake) and test-net-localport.js is a port-binding flake. Neither involves FFI, TinyCC, or Windows.

So: bun:ffi on Windows ARM64 works on this branch, end to end, on the real runner — no diagnostic noise this time. That closes the loop opened by the probe evidence (correct doubles/pointers/JSCallback and the fixed mov x30,#0x2000000000000; add x0,x0,x30 in the dumped JIT bytes).

Suggested order from here: land #33653 (this PR is a superset of it) or land this and close #33653 into it — either way this is what resolves #28055. #29476 duplicates the enablement with neither TinyCC fix and should close as superseded.

@robobun
robobun force-pushed the claude/ffi-windows-arm64 branch from f5e2f90 to fc228dc Compare July 14, 2026 21:23
@robobun

robobun commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Rebased onto current main (head fc228dc3) and re-verified end-to-end on a local Windows 11 ARM64 box:

Test file Result
test/js/bun/ffi/ffi.test.js 8 pass, 0 fail
test/js/bun/ffi/cc.test.ts + error-messages + viewSource 17 pass, 0 fail
test/napi/napi-value-ffi.test.ts 1 pass, 0 fail
test/js/node/fs/fs-writeSync-stdio-windows.test.ts 2 pass, 0 fail
test/js/node/fs/cp.test.ts (handle-leak test) 1 pass, 0 fail
test/js/node/process/process.test.js (versions) 2 pass, 0 fail

Fail-before: the canary bun on the same box throws bun:ffi cc()/callback() is not available in this build (TinyCC is disabled) for cc()/JSCallback; cc.test.ts -t double is 0 pass / 4 fail under it.

Also confirmed no regression on Windows x64 (26 pass / 0 fail across the same files) and Linux x64. cargo check -p bun_tcc_sys is clean on aarch64-pc-windows-msvc, x86_64-pc-windows-msvc, and host.

Swept arm64-gen.c/arm64-link.c/arm64-asm.c at the new TinyCC pin (8a6cbc12) for any remaining LLP64 hazards: none that affect codegen. The only residue is (long) casts of 64-bit addresses in a handful of tcc_error_noabort format args in arm64-link.c, so relocation error messages print truncated addresses on Windows; cosmetic.

Addressed the three comment-length / tempDir review notes in fc228dc3; threads resolved.

@robobun

robobun commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Adversarial review pass (on both this PR's diff and the full oven-sh/tinycc fork delta vs upstream), with the follow-ups applied at fb473c6b:

This PR survived every correctness probe; the one surviving concern was the #33653 stacking, now moot (#33653 and #29476 are closed as superseded).

TinyCC fork delta surfaced two substantive items:

  1. The run-time TLS guard at tccrun.c:344 checked only the two canonical .tdata/.tbss section pointers. A linked object built with gcc -fdata-sections emits per-symbol .tdata.<sym>/.tbss.<sym> sections that tcc_load_object_file keeps as separate SHF_TLS sections; the guard missed them and the Local-Exec accesses silently aliased the host's TLS block. Reachable from cc() since tcc_add_file() accepts object files. Fixed by scanning every section for SHF_TLS && data_offset (the same idiom tccelf.c and the *-link.c relocators already use), placed after pe_output_file/tcc_add_runtime so late-loaded objects are covered. Applied here as patches/tinycc/tccrun-shf-tls.patch; sent upstream to the fork as tccrun: reject TLS by SHF_TLS scan; add LLP64 regression cases to 73_arm64 tinycc#3 along with an LLP64 regression case for tests2/73_arm64.
  2. The TLS rejection test in cc.test.ts only covered initialized thread-locals (.tdata); the tbss arm of the guard was never exercised. Extended the matrix to four cases (both keywords × with/without initializer).

Re-verified on Windows 11 ARM64 at fb473c6b with the patch applied: cc.test.ts + ffi.test.js 21 pass / 0 fail; all four TLS cases correctly reject with "thread-local storage is not supported". No other LLP64 codegen hazards were found in arm64-gen.c/arm64-link.c/arm64-asm.c beyond a handful of diagnostic-printf (long) casts (truncated error-message addresses, no codegen impact).

@robobun

robobun commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Second adversarial pass, on oven-sh/tinycc#3 itself: approve-with-changes with one survivor. Placing the SHF_TLS scan after tcc_add_runtime also swept tcc's own runtime support objects, and under the documented libtcc1-usegcc=yes perf knob a gcc-built bcheck.o carries __thread int no_checking in .tbss, so every tcc -b -run on a TLS-free program would fail. Bun is unaffected (never passes -b, never loads bcheck.o, TCC_LIBTCC1=""), but it is a regression for upstream -b -run.

Fixed by keeping the scan at its original position before tcc_add_runtime: user inputs reach s1->sections via tcc_add_file() before tcc_relocate() runs, so split .tdata.<sym>/.tbss.<sym> from user objects are still caught, while tcc's own support objects are left alone. Verified: gcc -fdata-sections TLS .o still rejected; ./tcc -b -run hello.c with a gcc-built bcheck.o (.tbss present per readelf) still prints hello / exit 0.

3379760d updates the patch here to match tinycc#3 at e2643dcc; re-verified on Windows 11 ARM64 (cc.test.ts TLS/variadic/double cases 8 pass / 0 fail).

@claude claude 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.

No bugs found, but this enables a native JIT path (TinyCC) on a new platform along with a vendored-dep bump and a tccrun.c patch, so it warrants a human sign-off.

What was reviewed:

  • The three-way cfg.tinycc / ENABLE_TINYCC / tcc_externs! predicate stays in sync after dropping the windows-aarch64 arm.
  • __va_arg in libtcc1.c matches upstream lib/va_list.c semantics; the abort()→null-write substitution is intentional and gated to x86_64 SysV.
  • The SHF_TLS scan patch reuses locals i/s already in scope in tcc_relocate_ex and sits before pe_output_file/tcc_add_runtime per the follow-up commit.
  • Test un-gating: no remaining isFFIUnavailable references were left dangling after import removals.
Extended reasoning...

Overview

This PR enables bun:ffi on Windows ARM64 by (1) bumping the vendored TinyCC pin to oven-sh/tinycc@8a6cbc12 (which carries an LLP64 immediate-encoding fix in the arm64 backend), (2) removing the windows && arm64 exclusion from cfg.tinycc in config.ts, the generated ENABLE_TINYCC cfg predicate in buildOptionsRs.ts, and the tcc_externs! stub cfg in src/tcc_sys/tcc.rs, (3) adding a patches/tinycc/tccrun-shf-tls.patch that widens the run-time TLS guard to scan all SHF_TLS sections, (4) porting TinyCC's __va_arg into src/runtime/ffi/libtcc1.c (needed after the pin bump moved it out of tccdefs.h), and (5) un-gating ~8 test files that were skipped on windows-arm64 and adding new coverage for varargs, long-double varargs, and TLS rejection.

Security risks

FFI is inherently security-sensitive — it JIT-compiles user-provided C and executes it in-process. The specific risk surface this PR touches is TinyCC's arm64 codegen on an LLP64 host: the fork-side fix (not in this diff, but pulled in via the commit bump) changes how 64-bit immediates are classified for ADD/SUB encoding. A miscompile there produced wrong values and wild pointers pre-fix; the fix has been validated on real windows-11-aarch64 hardware in CI (build #71302) and locally at fc228dc3/fb473c6b. The TLS patch is defensive (rejects more inputs, not fewer). The __va_arg addition is a near-verbatim copy of upstream lib/va_list.c and is only reachable on x86_64 SysV targets. No new attack surface is introduced beyond what bun:ffi already exposes on other platforms.

Level of scrutiny

High. This is a platform enablement for a native-code JIT path, coupled with a vendored dependency bump whose actual code change (the LLP64 fix in arm64-gen.c) lives in a separate repo and is only referenced by commit hash. The build-config changes and test un-gating are mechanical, but the correctness of the whole PR hinges on the fork-side TinyCC fix and on the __va_arg port — both of which are C-ABI-level code where subtle mistakes manifest as memory corruption. Jarred-Sumner has been actively shepherding this (rebasing, sweeping for stragglers, validating CI), and the adversarial review pass in the timeline already caught and fixed two follow-ups (SHF_TLS scan scope, .tbss test coverage), but a maintainer approval is appropriate for a change of this scope.

Other factors

CI on the windows-11-aarch64 lane is green per the timeline (build #71302 and local re-verification at fb473c6b). All CodeRabbit nits (comment length, tempDir disposal) were addressed and threads resolved. #33653 and #29476 are closed as superseded. The process.versions.tinycc assertion in process.test.js matches the new pin. No outstanding unresolved review comments.

Jarred-Sumner and others added 7 commits July 20, 2026 05:22
Merges ~82 upstream commits (Jan-Jun 2026) into oven-sh/tinycc, keeping the
fork's macOS framework/dlsym and parser patches. Notable upstream fixes for
bun:ffi: x86_64 REX prefix miscompile when materializing 0 into r8-r15
(5th/6th integer args), an OOB read in tccrun after relocate with -g, and
arm64 long double comparison/negation fixes. The fork additionally makes
tcc_relocate flush the instruction cache on arm64 Windows.

Two upstream behavior changes needed handling here:

- __va_arg is no longer inlined by tcc's preprocessor and now lives in
  libtcc1, which Bun replaces with src/runtime/ffi/libtcc1.c; ship the
  function there (extern-free: the trampoline TCC states are -nostdlib).
  Without it, any va_arg in cc()-compiled C fails to relocate.
- Upstream now accepts _Thread_local/__thread and emits Local-Exec TLS,
  which is meaningless for in-memory relocation and aliases the host's
  thread block; the fork makes tcc_relocate reject TLS objects.

The fork also drops its Windows-ARM64 patches in favor of upstream's own
arm64-PE backend, and fixes an uninitialized pstrcat buffer in the macOS
framework path.
Upstream TinyCC now has an arm64-PE backend (merged in the previous commit),
so drop the windows-arm64 exclusion from cfg.tinycc, the generated
ENABLE_TINYCC constant, and the tcc_sys link stubs, and un-skip the FFI
tests that were gated on the platform. The fork also gained the
FlushInstructionCache call TinyCC's in-memory relocation needs on arm64
Windows.

Verified by cross-compiling bun.exe for aarch64-pc-windows-msvc from Linux
(TinyCC's arm64+PE objects compile with clang-cl and the binary links with
the real libtcc symbols); the windows-aarch64 CI lanes now run the bun:ffi
test suites.

Known parity notes, unchanged by this commit: cc() code with a stack frame
over 4 KB needs __chkstk, which Bun does not provide on any Windows target,
and long double helpers are not provided on any arm64 target.
On Windows, TinyCC itself is compiled by an LLP64 toolchain, and its arm64
backend used 'unsigned long' masks to decide whether a 64-bit constant fits
an add/sub immediate: (1ll << 49) was encoded as 'add ..., #0'. That constant
is JSC's DoubleEncodeOffset, so every double crossing bun:ffi's JIT'd
trampolines on Windows ARM64 lost the NaN-boxing offset (values off by one
exponent step) and pointer arguments decoded to wild addresses (segfaults).
Fixed in oven-sh/tinycc mob @ 8a6cbc12 by using uint64_t-typed masks.
Apply the SHF_TLS section scan from oven-sh/tinycc#3 as a build patch so
the guard also catches per-symbol .tdata.foo/.tbss.foo sections from
linked object files (gcc -fdata-sections). The previous two-pointer
check only saw the canonical .tdata/.tbss sections that tcc's own
codegen writes into.

Extend the cc.test.ts TLS matrix to include uninitialized thread-locals,
which land in .tbss rather than .tdata, so both arms of the guard are
exercised.
Placing the scan after tcc_add_runtime also swept tcc's own support
objects, which under the documented libtcc1-usegcc=yes knob makes every
"tcc -b -run" fail on a TLS-free program (gcc-built bcheck.o carries a
__thread no_checking in .tbss). User inputs are added via tcc_add_file
before tcc_relocate runs, so the original position already covers them.
Matches oven-sh/tinycc#3 at e2643dcc.
The SHF_TLS section-scan guard is now in the fork's mob branch, so drop
the build-time patch that carried it.
@robobun
robobun force-pushed the claude/ffi-windows-arm64 branch from 3379760 to e83d3d0 Compare July 20, 2026 05:31

@claude claude 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.

I didn't find any bugs, but this enables the TinyCC JIT on a new platform, bumps the vendored TinyCC pin, and adds a new __va_arg runtime helper — worth a human look before landing.

What was reviewed:

  • The three-way cfg.tinycc / ENABLE_TINYCC / tcc_externs! predicate stays consistent (all now !(android || freebsd)).
  • The new __va_arg in libtcc1.c matches upstream TinyCC's lib/va_list.c minus the abort() reference; correctly gated to __x86_64__ && !_WIN32.
  • Un-gated tests: each removed isFFIUnavailable guard was purely the win-arm64 exclusion; no other condition was dropped.
  • process.versions.tinycc assertion and TINYCC_COMMIT agree; patches/tinycc/ now holds only tcc.h.patch (the SHF_TLS patch was upstreamed into the new pin).
Extended reasoning...

Overview

This PR enables bun:ffi (TinyCC) on Windows ARM64. It touches four layers that must agree: the build-config default (config.ts), the generated Rust constant (buildOptionsRs.ts), the Rust FFI link stubs (tcc_sys/tcc.rs), and the dep enable predicate (deps/tinycc.ts). It also bumps the vendored TinyCC commit to 05f0fafa (carrying the LLP64 arm64-immediate fix and the SHF_TLS run-time TLS guard fix), adds an x86_64-SysV __va_arg implementation to Bun's libtcc1.c (needed because the newer TinyCC no longer inlines it in tccdefs.h), and un-skips ~10 FFI test gates plus adds new variadic/TLS coverage in cc.test.ts.

Security risks

FFI JIT-compiles and executes arbitrary user C at runtime. Enabling it on a new target is inherently security-relevant: a codegen bug (like the LLP64 immediate miscompile this PR fixes in the fork) can turn into memory corruption or type confusion in the host process. The new __va_arg runtime helper is compiled by TinyCC into every cc() on x86_64 SysV; it does raw pointer arithmetic on the caller's register-save area. It is a near-verbatim copy of upstream's lib/va_list.c, and the new tests exercise integer/float/struct/overflow-area paths, but it is still new code on a hot boundary.

Level of scrutiny

High. Per the repo's own guidance, this hits both Dependencies & vendoring (TinyCC pin bump) and Cross-platform (enabling a platform-gated native code path). The change is not mechanical — the correctness of the enablement rests on a codegen fix in an external fork, and the __va_arg addition affects every non-Windows x64 cc() call, not just the newly-enabled platform.

Other factors

The PR has been actively shepherded by a maintainer (rebased, CI-verified on real windows-11-aarch64 hardware, adversarial review passes on both the diff and the fork delta), and all CodeRabbit threads are resolved. Test coverage for the new code is good (variadic ints/doubles/structs/long-double, TLS rejection across .tdata/.tbss). Nothing looks wrong to me, but the combination of a vendored-dep bump, a new native runtime helper, and a platform enablement is exactly the shape that warrants a human sign-off rather than a bot approval.

@dylan-conway
dylan-conway merged commit f64cade into main Jul 20, 2026
79 checks passed
@dylan-conway
dylan-conway deleted the claude/ffi-windows-arm64 branch July 20, 2026 06:35
robobun added a commit that referenced this pull request Aug 13, 2026
…sts on arm64

The node directory iterator now asks NtQueryDirectoryFile for
FileFullDirectoryInformation, whose EaSize field is the reparse tag of a
reparse-point entry, and hands attributes and tag to the cp walkers. A
walked reparse entry is classified from the listing alone and the result
travels with the CpSingleTask, so the copy neither re-stats nor opens it;
the path-based lookup remains for the top-level operand and for listings
without a tag. readdir ignores the extra field.

bun:ffi works on Windows arm64 since #33696, so the tests no longer skip
there, and the link cases now check the link flavor and target.
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.

Support bun:ffi on Windows ARM64

3 participants