diff --git a/scripts/build/buildOptionsRs.ts b/scripts/build/buildOptionsRs.ts index 2768f71bf0ea..70ab863a4101 100644 --- a/scripts/build/buildOptionsRs.ts +++ b/scripts/build/buildOptionsRs.ts @@ -68,7 +68,6 @@ export function generateBuildOptionsRs(cfg: Config): string { "pub const ENABLE_LOGS: bool = cfg!(bun_debug);", "pub const ENABLE_ASAN: bool = cfg!(bun_asan);", "pub const ENABLE_TINYCC: bool = !cfg!(any(", - ` all(windows, target_arch = "aarch64"),`, ` target_os = "android",`, ` target_os = "freebsd",`, "));", diff --git a/scripts/build/config.ts b/scripts/build/config.ts index 0d7a8fd4ee4c..0da4cc90dadc 100644 --- a/scripts/build/config.ts +++ b/scripts/build/config.ts @@ -867,10 +867,9 @@ export function resolveConfig(partial: PartialConfig, toolchain: Toolchain): Con // failure is loud ("cannot find -l:libatomic.a") and the fix is obvious. const staticLibatomic = partial.staticLibatomic ?? true; - // TinyCC: off on Windows ARM64 (not supported), Android (no upstream - // bionic support; FFI cc() falls back to dlopen-only), and FreeBSD - // (oven-sh/tinycc has no FreeBSD target). - const tinycc = partial.tinycc ?? !((windows && arm64) || abi === "android" || freebsd); + // TinyCC: off on Android (no upstream bionic support; FFI cc() falls back + // to dlopen-only) and FreeBSD (oven-sh/tinycc has no FreeBSD target). + const tinycc = partial.tinycc ?? !(abi === "android" || freebsd); const valgrind = partial.valgrind ?? false; const fuzzilli = partial.fuzzilli ?? false; diff --git a/scripts/build/deps/tinycc.ts b/scripts/build/deps/tinycc.ts index 499a83bc16df..7fa186cde0b5 100644 --- a/scripts/build/deps/tinycc.ts +++ b/scripts/build/deps/tinycc.ts @@ -2,7 +2,7 @@ * TinyCC — small embeddable C compiler. Powers bun:ffi's JIT-compile path, * where user-provided C gets compiled and linked at runtime. * - * Disabled on windows-arm64 (tinycc doesn't have an arm64-coff backend). + * Disabled on Android and FreeBSD — see cfg.tinycc in config.ts. * * Built via DirectBuild — no cmake sub-process. The old overlay * CMakeLists.txt had two recurring ASAN workarounds for the c2str host @@ -12,14 +12,13 @@ import type { Dependency, DirectBuild } from "../source.ts"; -const TINYCC_COMMIT = "12882eee073cfe5c7621bcfadf679e1372d4537b"; +const TINYCC_COMMIT = "05f0fafaa3be31e31d7b4b5c17dc60f62c991171"; export const tinycc: Dependency = { name: "tinycc", versionMacro: "TINYCC", - // The cfg.tinycc flag already encodes the windows-arm64 exclusion - // (see config.ts: `tinycc ?? !(windows && arm64)`). + // cfg.tinycc encodes the platform exclusions (config.ts). enabled: cfg => cfg.tinycc, source: () => ({ diff --git a/scripts/build/source.ts b/scripts/build/source.ts index 92fc48cfac75..cbad9e8a56b1 100644 --- a/scripts/build/source.ts +++ b/scripts/build/source.ts @@ -446,7 +446,7 @@ export interface Dependency { /** * Whether this dep participates in the build at all. Defaults to always-on. - * E.g. libuv is windows-only, tinycc is disabled on windows-arm64. + * E.g. libuv is windows-only, tinycc is disabled on Android/FreeBSD. */ enabled?: (cfg: Config) => boolean; diff --git a/src/runtime/ffi/libtcc1.c b/src/runtime/ffi/libtcc1.c index 38750b825feb..ff8174d1157d 100644 --- a/src/runtime/ffi/libtcc1.c +++ b/src/runtime/ffi/libtcc1.c @@ -604,3 +604,55 @@ unsigned long long __fixunsxfdi (long double a1) else return 0; } + +/* TinyCC lib/va_list.c (x86_64 SysV only): __va_arg is no longer inlined and + Bun supplies libtcc1 from this file. No extern abort(): Bun never injects + that symbol, so referencing it would fail every cc() at relocate. */ +#if defined(__x86_64__) && !defined(_WIN32) + +enum __va_arg_type { + __va_gen_reg, __va_float_reg, __va_stack +}; + +void *__va_arg(__builtin_va_list ap, + int arg_type, + int size, int align) +{ + size = (size + 7) & ~7; + align = (align + 7) & ~7; + switch ((enum __va_arg_type)arg_type) { + case __va_gen_reg: + if (ap->gp_offset + size <= 48) { + ap->gp_offset += size; + return ap->reg_save_area + ap->gp_offset - size; + } + goto use_overflow_area; + + case __va_float_reg: + if (ap->fp_offset < 128 + 48) { + ap->fp_offset += 16; + if (size == 8) + return ap->reg_save_area + ap->fp_offset - 16; + if (ap->fp_offset < 128 + 48) { + double *p = (double *)(ap->reg_save_area + ap->fp_offset); + p[-1] = p[0]; + ap->fp_offset += 16; + return ap->reg_save_area + ap->fp_offset - 32; + } + } + goto use_overflow_area; + + case __va_stack: + use_overflow_area: + ap->overflow_arg_area += size; + ap->overflow_arg_area = (char*)((long long)(ap->overflow_arg_area + align - 1) & -align); + return ap->overflow_arg_area - size; + + default: + /* unreachable: the compiler only emits the three classes above. + Trap with a null write like TinyCC's old inline __va_arg did. */ + *(volatile char *)0 = 0; + return 0; + } +} +#endif /* __x86_64__ && !_WIN32 */ diff --git a/src/tcc_sys/tcc.rs b/src/tcc_sys/tcc.rs index bce7137ccfd7..53d3838122ea 100644 --- a/src/tcc_sys/tcc.rs +++ b/src/tcc_sys/tcc.rs @@ -12,9 +12,8 @@ pub type TCCErrorFunc = Option = unsafe extern "C" fn(ctx: *mut Ctx, msg: *const c_char); // `libtcc.a` is only built where `cfg.tinycc` is true (`scripts/build/config.ts`): -// not Windows/aarch64 (TinyCC has no aarch64-pe-coff backend), not Android, not -// FreeBSD (the vendored fork doesn't support those targets). On those platforms -// these `extern "C"` decls would be undefined at link: +// not Android, not FreeBSD (the vendored fork doesn't support those targets). +// On those platforms these `extern "C"` decls would be undefined at link: // `bun_runtime::ffi::ffi_body::{Source::add, // CompileC::compile}` are reachable from `extern "C"` JS bindings and the // monomorphized refs land in `libbun_rust.a` regardless of any @@ -24,15 +23,16 @@ pub type ErrorFunc = unsafe extern "C" fn(ctx: *mut Ctx, msg: *const c_char // in this build"), and the `unreachable!()` makes any future gate regression // loud rather than silently UB. // -// Keep this predicate in sync with `cfg.tinycc` in `scripts/build/config.ts`. +// Keep this predicate in sync with `cfg.tinycc` in `scripts/build/config.ts` +// and `ENABLE_TINYCC` in `scripts/build/buildOptionsRs.ts`. macro_rules! tcc_externs { ($($(#[$attr:meta])* fn $name:ident($($arg:ident: $ty:ty),* $(,)?) $(-> $ret:ty)?;)*) => { - #[cfg(not(any(target_os = "android", target_os = "freebsd", all(windows, target_arch = "aarch64"))))] + #[cfg(not(any(target_os = "android", target_os = "freebsd")))] unsafe extern "C" { $($(#[$attr])* fn $name($($arg: $ty),*) $(-> $ret)?;)* } $( - #[cfg(any(target_os = "android", target_os = "freebsd", all(windows, target_arch = "aarch64")))] + #[cfg(any(target_os = "android", target_os = "freebsd"))] #[allow(unused_variables, clippy::missing_safety_doc)] unsafe extern "C" fn $name($($arg: $ty),*) $(-> $ret)? { unreachable!(concat!( diff --git a/test/js/bun/ffi/cc.test.ts b/test/js/bun/ffi/cc.test.ts index 15b959aa9c18..828f0c96d06d 100644 --- a/test/js/bun/ffi/cc.test.ts +++ b/test/js/bun/ffi/cc.test.ts @@ -1,16 +1,13 @@ import { cc, CString, JSCallback, ptr, type FFIFunction, type Library } from "bun:ffi"; import { afterAll, beforeAll, describe, expect, it } from "bun:test"; import { promises as fs } from "fs"; -import { bunEnv, bunExe, isArm64, isASAN, isWindows, normalizeBunSnapshot, tempDir, tempDirWithFiles } from "harness"; +import { bunEnv, bunExe, isASAN, isWindows, normalizeBunSnapshot, tempDir, tempDirWithFiles } from "harness"; import path from "path"; -// TinyCC (and all of bun:ffi) is disabled on Windows ARM64 -const isFFIUnavailable = isWindows && isArm64; - // TODO: we need to install build-essential and Apple SDK in CI. // It can't find includes. It can on machines with that enabled. // TinyCC's setjmp/longjmp error handling conflicts with ASan. -it.todoIf(isWindows || isASAN || isFFIUnavailable)("can run a .c file", () => { +it.todoIf(isWindows || isASAN)("can run a .c file", () => { const result = Bun.spawnSync({ cmd: [bunExe(), path.join(__dirname, "cc-fixture.js")], cwd: __dirname, @@ -22,8 +19,7 @@ it.todoIf(isWindows || isASAN || isFFIUnavailable)("can run a .c file", () => { }); // TinyCC's setjmp/longjmp error handling conflicts with ASan. -// TinyCC is disabled on Windows ARM64. -describe.skipIf(isASAN || isFFIUnavailable)("given an add(a, b) function", () => { +describe.skipIf(isASAN)("given an add(a, b) function", () => { const source = /* c */ ` int add(int a, int b) { return a + b; @@ -391,7 +387,7 @@ describe.skipIf(isWindows || isASAN)("threadsafe JSCallback invoked from a forei // Pins GC liveness: compiled trampolines survive the library wrapper being // collected, and a JSCallback's closure stays alive until close(). // TinyCC's setjmp/longjmp error handling conflicts with ASan. -describe.skipIf(isASAN || isFFIUnavailable)("GC liveness of compiled symbols and callbacks", () => { +describe.skipIf(isASAN)("GC liveness of compiled symbols and callbacks", () => { it("keeps symbol functions and callback closures alive across forced GC", async () => { using dir = tempDir("bun-ffi-cc-gc-liveness", { "lib.c": /* c */ ` @@ -457,7 +453,192 @@ describe.skipIf(isASAN || isFFIUnavailable)("GC liveness of compiled symbols and }); }); -describe.skipIf(isFFIUnavailable)("double <-> JSValue conversions", () => { +// va_arg on x86_64 SysV lowers to a call to __va_arg, which TinyCC expects +// libtcc1 to provide; Bun replaces libtcc1 with src/runtime/ffi/libtcc1.c. +// TinyCC's setjmp/longjmp error handling conflicts with ASan. +describe.skipIf(isASAN)("variadic functions inside cc()-compiled C", () => { + it("va_arg over ints, doubles, and the stack overflow area", async () => { + using dir = tempDir("bun-ffi-cc-varargs", { + "varargs.c": /* c */ ` + #include + + static long long sum_ints(int count, ...) { + va_list ap; + va_start(ap, count); + long long total = 0; + for (int i = 0; i < count; i++) total += va_arg(ap, int); + va_end(ap); + return total; + } + + static double sum_doubles(int count, ...) { + va_list ap; + va_start(ap, count); + double total = 0; + for (int i = 0; i < count; i++) total += va_arg(ap, double); + va_end(ap); + return total; + } + + /* alternating int/double reads from one va_list: gp_offset and + fp_offset must advance independently */ + static double sum_pairs(int count, ...) { + va_list ap; + va_start(ap, count); + double total = 0; + for (int i = 0; i < count; i++) { + total += va_arg(ap, int); + total += va_arg(ap, double); + } + va_end(ap); + return total; + } + + /* a 16-byte all-double struct occupies two SSE register save slots */ + struct dd { double a, b; }; + static double sum_dd(int count, ...) { + va_list ap; + va_start(ap, count); + double total = 0; + for (int i = 0; i < count; i++) { + struct dd v = va_arg(ap, struct dd); + total += v.a + v.b; + } + va_end(ap); + return total; + } + + /* 10 ints: exhausts the 6 integer registers and spills to the stack. */ + long long ten_ints(void) { return sum_ints(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); } + /* 10 doubles: exhausts the 8 SSE registers and spills to the stack. */ + double ten_doubles(void) { return sum_doubles(10, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5); } + double interleaved(void) { return sum_pairs(9, 1,0.5, 2,0.5, 3,0.5, 4,0.5, 5,0.5, 6,0.5, 7,0.5, 8,0.5, 9,0.5); } + double double_pairs(void) { + struct dd x = { 1.5, 2.5 }, y = { 3.0, 4.0 }; + return sum_dd(2, x, y); + } + `, + "fixture.js": /* js */ ` + import { cc } from "bun:ffi"; + import path from "path"; + + const { symbols } = cc({ + source: path.join(import.meta.dir, "varargs.c"), + symbols: { + ten_ints: { args: [], returns: "i64" }, + ten_doubles: { args: [], returns: "f64" }, + interleaved: { args: [], returns: "f64" }, + double_pairs: { args: [], returns: "f64" }, + }, + }); + console.log( + JSON.stringify({ + ten_ints: Number(symbols.ten_ints()), + ten_doubles: symbols.ten_doubles(), + interleaved: symbols.interleaved(), + double_pairs: symbols.double_pairs(), + }), + ); + `, + }); + + await using proc = Bun.spawn({ + cmd: [bunExe(), "fixture.js"], + env: bunEnv, + cwd: String(dir), + stderr: "pipe", + }); + + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + + // stderr is included in the received object so failures show it, but is not + // asserted empty: debug builds emit benign startup warnings. + const results = stdout.startsWith("{") ? JSON.parse(stdout) : stdout; + expect({ results, stderr, exitCode }).toMatchObject({ + results: { + ten_ints: 55, + ten_doubles: 50, + interleaved: 49.5, + double_pairs: 11, + }, + exitCode: 0, + }); + }); +}); + +// long double is 16 bytes on x86_64 and always va_arg'd through the stack; on +// aarch64 it is binary128 and its arithmetic needs soft-float helpers +// (__addtf3, ...) that Bun's TCC states do not provide, so x64 only. +describe.skipIf(isASAN || process.arch !== "x64")("long double varargs inside cc()-compiled C", () => { + it("va_arg over long double", async () => { + using dir = tempDir("bun-ffi-cc-varargs-ld", { + "ld.c": /* c */ ` + #include + + static double sum_long_doubles(int count, ...) { + va_list ap; + va_start(ap, count); + long double total = 0; + for (int i = 0; i < count; i++) total += va_arg(ap, long double); + va_end(ap); + return (double)total; + } + + double long_doubles(void) { return sum_long_doubles(3, 1.5L, 2.25L, 3.25L); } + `, + "fixture.js": /* js */ ` + import { cc } from "bun:ffi"; + import path from "path"; + + const { symbols } = cc({ + source: path.join(import.meta.dir, "ld.c"), + symbols: { long_doubles: { args: [], returns: "f64" } }, + }); + console.log(JSON.stringify({ long_doubles: symbols.long_doubles() })); + `, + }); + + await using proc = Bun.spawn({ + cmd: [bunExe(), "fixture.js"], + env: bunEnv, + cwd: String(dir), + stderr: "pipe", + }); + + const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + + const results = stdout.startsWith("{") ? JSON.parse(stdout) : stdout; + expect({ results, stderr, exitCode }).toMatchObject({ + results: { long_doubles: 7 }, + exitCode: 0, + }); + }); +}); + +// TinyCC emits Local-Exec TLS, which has no PT_TLS segment to target under +// in-memory relocation and would alias the host's own thread block; it must be +// rejected up front instead of silently corrupting Bun's thread-locals. +describe.skipIf(isASAN)("thread-local storage inside cc()-compiled C", () => { + it.each([ + ["_Thread_local", " = 0"], + ["__thread", " = 0"], + // No initializer: lands in .tbss, so the guard's tbss/SHF_TLS arm is covered too. + ["_Thread_local", ""], + ["__thread", ""], + ])("%s int x%s; is a compile error", (keyword, init) => { + using dir = tempDir("bun-ffi-cc-tls", { + "tls.c": `${keyword} int bun_test_tls_counter${init};\nint bump(void) { return ++bun_test_tls_counter; }\n`, + }); + expect(() => { + cc({ + source: path.join(String(dir), "tls.c"), + symbols: { bump: { args: [], returns: "int" } }, + }); + }).toThrow(/thread-local storage is not supported/); + }); +}); + +describe("double <-> JSValue conversions", () => { // JSC NaN-boxes doubles, so a NaN whose payload collides with the tag space // ("impure NaN", see JSC's PureNaN.h) must never be encoded as-is: it would // decode as a native-chosen JSValue (true, undefined, an Int32, or a cell diff --git a/test/js/bun/ffi/ffi-error-messages.test.ts b/test/js/bun/ffi/ffi-error-messages.test.ts index 70dae5e2a7c9..23cf35c76454 100644 --- a/test/js/bun/ffi/ffi-error-messages.test.ts +++ b/test/js/bun/ffi/ffi-error-messages.test.ts @@ -1,11 +1,8 @@ import { dlopen, linkSymbols } from "bun:ffi"; import { describe, expect, test } from "bun:test"; -import { isArm64, isMusl, isWindows } from "harness"; +import { isMusl } from "harness"; -// TinyCC (and all of bun:ffi) is disabled on Windows ARM64 -const isFFIUnavailable = isWindows && isArm64; - -describe.skipIf(isFFIUnavailable)("FFI error messages", () => { +describe("FFI error messages", () => { test("dlopen shows library name when library cannot be opened", () => { // Try to open a non-existent library try { diff --git a/test/js/bun/ffi/ffi-viewSource-non-object.test.ts b/test/js/bun/ffi/ffi-viewSource-non-object.test.ts index 48ea21ad60a5..57697b1195dc 100644 --- a/test/js/bun/ffi/ffi-viewSource-non-object.test.ts +++ b/test/js/bun/ffi/ffi-viewSource-non-object.test.ts @@ -1,8 +1,5 @@ import { JSCallback, viewSource } from "bun:ffi"; import { describe, expect, test } from "bun:test"; -import { isArm64, isWindows } from "harness"; - -const isFFIUnavailable = isWindows && isArm64; // Captures what a call throws, or undefined if it returned normally. Written // explicitly so the assertions below distinguish a thrown Error from a @@ -16,7 +13,7 @@ function thrown(fn: () => unknown): unknown { return undefined; } -describe.skipIf(isFFIUnavailable)("FFI viewSource", () => { +describe("FFI viewSource", () => { // Descriptor values must be objects like { args: [...], returns: "void" }. // https://github.com/oven-sh/bun/pull/28361, https://github.com/oven-sh/bun/pull/34396 test.each([42, "not_an_object", true])("throws on non-object symbol descriptor value %p", value => { @@ -54,7 +51,7 @@ describe.skipIf(isFFIUnavailable)("FFI viewSource", () => { }); }); -describe.skipIf(isFFIUnavailable)("FFI JSCallback", () => { +describe("FFI JSCallback", () => { test.each([null, undefined, 42, "str", true])("throws on non-object options %p", value => { const err = thrown(() => new JSCallback(() => {}, value as any)); expect(err).toBeInstanceOf(TypeError); diff --git a/test/js/bun/ffi/ffi.test.js b/test/js/bun/ffi/ffi.test.js index 2546e1d1fcfd..f2548bfd9543 100644 --- a/test/js/bun/ffi/ffi.test.js +++ b/test/js/bun/ffi/ffi.test.js @@ -1,6 +1,6 @@ import { afterAll, describe, expect, it } from "bun:test"; import { existsSync } from "fs"; -import { bunEnv, bunExe, isArm64, isGlibcVersionAtLeast, isWindows, tempDir } from "harness"; +import { bunEnv, bunExe, isGlibcVersionAtLeast, isWindows, tempDir } from "harness"; import { platform } from "os"; import { @@ -666,13 +666,10 @@ it("dlopen throws an error instead of returning it", () => { expect(err).toBeTruthy(); }); -// TinyCC, which implements JSCallback and CFunction, is unavailable on Windows ARM64. -const isFFIUnavailable = isWindows && isArm64; - // Windows: dlopen must accept paths with non-ASCII characters. Previously the // path was handed to LoadLibraryA as UTF-8, which the OS decodes as the system // ANSI codepage, so any non-ASCII byte mangled the path. -it.skipIf(!isWindows || isFFIUnavailable)("dlopen accepts non-ASCII library paths on Windows", async () => { +it.skipIf(!isWindows)("dlopen accepts non-ASCII library paths on Windows", async () => { const fixture = ` const { dlopen, FFIType } = require("bun:ffi"); const { mkdirSync, copyFileSync } = require("node:fs"); @@ -720,7 +717,7 @@ it(".ptr is not leaked", () => { // Runs in a subprocess: `bun test`'s exit path does not finalize the CFunction's native handle, // which the ASan lane's leak checker then reports against this file. -it.skipIf(isFFIUnavailable)("JSCallback exceptions propagate out of the native call", async () => { +it("JSCallback exceptions propagate out of the native call", async () => { await using proc = Bun.spawn({ cmd: [ bunExe(), @@ -757,7 +754,7 @@ it.skipIf(isFFIUnavailable)("JSCallback exceptions propagate out of the native c // worker.terminate() delivered inside a threadsafe JSCallback used to trip // "ASSERTION FAILED: !isTerminationException(exception) || hasTerminationRequest()" // in JSC::VM::setException on the worker thread and re-enter the terminated VM. -it.skipIf(isFFIUnavailable)("JSCallback tolerates worker.terminate() arriving inside the callback", async () => { +it("JSCallback tolerates worker.terminate() arriving inside the callback", async () => { using dir = tempDir("ffi-jscallback-terminate", { "main.js": ` import { join } from "node:path"; diff --git a/test/js/node/fs/cp.test.ts b/test/js/node/fs/cp.test.ts index d4e11c89a286..d554096a6cf4 100644 --- a/test/js/node/fs/cp.test.ts +++ b/test/js/node/fs/cp.test.ts @@ -1,6 +1,6 @@ import { describe, expect, jest, test } from "bun:test"; import fs from "fs"; -import { bunEnv, bunExe, isArm64, isLinux, isPosix, isWindows, tempDir, tempDirWithFiles } from "harness"; +import { bunEnv, bunExe, isLinux, isPosix, isWindows, tempDir, tempDirWithFiles } from "harness"; import { mkfifo } from "mkfifo"; import { isAbsolute, join } from "path"; @@ -434,8 +434,8 @@ test("cp with missing callback throws", () => { // source symlink to resolve its target via GetFinalPathNameByHandleW. Previously // that handle was never closed, leaking one OS handle per symlink copied. Over a // large tree (e.g. node_modules with junctions) this eventually exhausts the -// process handle table. bun:ffi (TinyCC) is unavailable on Windows arm64. -test.skipIf(!isWindows || isArm64)("cpSync over symlinks does not leak Windows handles", () => { +// process handle table. +test.skipIf(!isWindows)("cpSync over symlinks does not leak Windows handles", () => { const { dlopen } = require("bun:ffi"); const k32 = dlopen("kernel32.dll", { GetCurrentProcess: { args: [], returns: "ptr" }, diff --git a/test/js/node/fs/fs-writeSync-stdio-windows.test.ts b/test/js/node/fs/fs-writeSync-stdio-windows.test.ts index 8ec25e4fb867..5fd09ddf3e88 100644 --- a/test/js/node/fs/fs-writeSync-stdio-windows.test.ts +++ b/test/js/node/fs/fs-writeSync-stdio-windows.test.ts @@ -8,14 +8,11 @@ // Now `fromJS`/`fromJSValidated` return `.fromUV(0|1|2)` directly, and // `FD.uv()` checks the cached stdio handles before `GetStdHandle`. import { describe, expect, test } from "bun:test"; -import { bunEnv, bunExe, isArm64, isWindows, tempDir } from "harness"; +import { bunEnv, bunExe, isWindows, tempDir } from "harness"; import { join } from "node:path"; describe.concurrent.skipIf(!isWindows)("fs.writeSync on Windows stdio/handles", () => { - // bun:ffi (TinyCC) is unavailable on Windows arm64, so this repro can only - // run on x64. The second test below covers the plain openSync→writeSync path - // on all Windows arches. - test.skipIf(isArm64)("fs.writeSync(1, ...) does not panic after SetStdHandle swaps stdout", async () => { + test("fs.writeSync(1, ...) does not panic after SetStdHandle swaps stdout", async () => { const fixture = ` const fs = require("node:fs"); const { dlopen } = require("bun:ffi"); diff --git a/test/js/node/process/process.test.js b/test/js/node/process/process.test.js index 33a44ccbc342..59e0ba874279 100644 --- a/test/js/node/process/process.test.js +++ b/test/js/node/process/process.test.js @@ -336,7 +336,7 @@ it("process.versions", () => { mimalloc: "acd9924a0af3ba7c341910b48815106f2944ffa0", picohttpparser: "066d2b1e9ab820703db0837a7255d92d30f0c9f5", zlib: "12731092979c6d07f42da27da673a9f6c7b13586", - tinycc: "12882eee073cfe5c7621bcfadf679e1372d4537b", + tinycc: "05f0fafaa3be31e31d7b4b5c17dc60f62c991171", lolhtml: "77127cd2b8545998756e8d64e36ee2313c4bb312", ares: "3ac47ee46edd8ea40370222f91613fc16c434853", libdeflate: "c8c56a20f8f621e6a966b716b31f1dedab6a41e3", diff --git a/test/napi/napi-value-ffi.test.ts b/test/napi/napi-value-ffi.test.ts index 3abac7617870..8dfba97bb511 100644 --- a/test/napi/napi-value-ffi.test.ts +++ b/test/napi/napi-value-ffi.test.ts @@ -2,14 +2,14 @@ import { spawnSync } from "bun"; import { cc, dlopen } from "bun:ffi"; import { beforeAll, describe, expect, it } from "bun:test"; import { existsSync, statSync } from "fs"; -import { bunEnv, bunExe, canBuildNodeAddons, isArm64, isASAN, isWindows } from "harness"; +import { bunEnv, bunExe, canBuildNodeAddons, isASAN, isWindows } from "harness"; import { join } from "path"; import source from "./napi-app/ffi_addon_1.c" with { type: "file" }; -// TinyCC (and all of bun:ffi) is disabled on Windows ARM64; the napi-app -// fixture needs a toolchain that can compile the reported Node headers. -const isFFIUnavailable = (isWindows && isArm64) || !canBuildNodeAddons(); +// The napi-app fixture needs a toolchain that can compile the reported +// Node headers. +const isFFIUnavailable = !canBuildNodeAddons(); const symbols = { set_instance_data: {