Conversation
… crate's exports against their callers The dead-code sweep in #37332 removed these two extern declarations from bun_libuv_sys, but #31829 (merged in between) had started calling them from cfg(windows) code in node_util_binding.rs, node_cluster_binding.rs and ipc_host.rs, so the Windows build of bun_runtime fails with E0425 on main. Both sides of this crate are cfg(windows), so a non-Windows cargo check cannot see the mismatch. The new source lint resolves every crate-root name the rest of src/ reaches through bun_libuv_sys (directly, via bun_sys::windows::libuv, or via a local alias) against the items the crate exports, and reports the three call sites on any host.
|
Warning Review limit reached
Next review available in: 29 seconds Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
Updated 4:20 PM PT - Aug 14th, 2026
⏳ @robobun, your commit 79439a8 is still building in
|
|
Status: closed as a duplicate of #38733, which was opened a minute earlier with the same fix (the identical 4-line restore of For the record: main's Windows |
There was a problem hiding this comment.
LGTM — restores two extern "C" declarations that #37332 removed while cfg(windows) callers still use them, plus a source lint to catch the next instance.
What was reviewed:
- Signatures match
uv.h(int uv_translate_sys_error(int),uv_pid_t uv_os_getppid(void));uv_pid_tis already defined at libuv.rs:91. - Confirmed the three call sites exist as described (
node_cluster_binding.rs:391,node_util_binding.rs:75,ipc_host.rs:374) and wrap the calls inunsafe. - The lint follows the established
test/internal/source-lints/pattern, guards against vacuous passes (resolved > 0, anchor names), and flags any newpub use ... ::*glob it doesn't follow.
Extended reasoning...
Overview
Two changes: (1) restore uv_translate_sys_error and uv_os_getppid in src/libuv_sys/libuv.rs's extern "C" block — 4 added lines total; (2) add test/internal/source-lints/libuv-sys-exports.test.ts, a ~190-line regex-based lint that resolves every bun_libuv_sys::<item> reference in src/**/*.rs against the crate's actual exports so a future removal of a still-used declaration fails on any host without a Windows toolchain.
Security risks
None. The Rust change only re-adds FFI declarations for functions libuv already exports (and which are already listed in symbols.def/symbols.dyn/linker scripts). The test only reads source files and runs git ls-tree; it introduces no runtime behavior.
Level of scrutiny
Low for the core fix — it's a mechanical restore of declarations deleted by an over-eager dead-code sweep, and main's Windows build is currently broken without it. I verified the signatures against src/jsc/bindings/libuv/uv.h:421,1289 and confirmed uv_pid_t is still defined (libuv.rs:91). The three call sites the PR names all exist and call these via unsafe { bun_libuv_sys::... }, so plain (non-safe) declarations are correct.
Medium for the lint — it's heuristic regex over rustfmt-formatted source, but it lives beside ~24 sibling lints of the same shape in test/internal/source-lints/ and follows their conventions (module-scope scan, comment-stripping, tracked-file gating via git ls-tree). It defends against silent decay: an anchor test asserts each declaration shape (struct, extern fn, trait, module, constant, re-export) is actually parsed, unfollowedGlobs fails loudly if a new pub use ... ::* appears, and resolved > 0 prevents an empty scan from passing. The PR description confirms it fails on the pre-fix tree naming exactly the three sites rustc names, and passes after — satisfying the "prove the test fails for the right reason" requirement.
Other factors
No prior reviews or outstanding comments. The PR is a build-fix for main (Windows lanes are red on build 96727), so urgency favors landing. test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts (the pin list from #37332) does not list either symbol, so no conflict there.
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
|
Duplicate of #38733, which was opened first with the same change. Closing this one in its favor. |
Problem
:windows: x64 - build-bunand:windows: aarch64 - build-bun, main build 96727 and every PR build based on it, e.g. 96732), so every Windows test lane fails with it:uv_translate_sys_erroranduv_os_getppiddeclarations fromsrc/libuv_sys/libuv.rs. They were unused when that PR was verified, but cluster: port Node's cluster and child_process handle-passing suites (+43 upstream tests; cluster 54 → 85) and implement what they expose — round-robin fd handoff, SCHED_NONE shared handles, UDP clustering, IPC handle passing #31829 landed in between and calls both fromcfg(windows)code (src/runtime/node/node_util_binding.rs:75,src/runtime/node/node_cluster_binding.rs:391,src/runtime/ipc_host.rs:374).libuv.rsis#![cfg(windows)]and so are the three call sites, socargo check/bun bdon Linux or macOS compiles neither side.Fix
src/libuv_sys/libuv.rs: restore the twoextern "C"declarations, byte for byte as they were before Remove dead code from libuv_sys, cares_sys, simdutf FFI, test_runner, and C++ bindings #37332 (uv_translate_sys_error(c_int) -> c_int,uv_os_getppid() -> uv_pid_t). Both matchuv.h; the call sites still wrap them inunsafe, so the plain (non-safe) declarations are the ones that compile without warnings.test/internal/source-lints/libuv-sys-exports.test.ts: a source lint that collects every crate-root itembun_libuv_sysexports (column-0pubitems,extern "C"block contents,pub usere-exports,lib.rsconstants) and resolves every name the rest ofsrc/reaches through the crate against it:bun_libuv_sys::x,bun_sys::windows::libuv::x, items pulled in withuse, and paths through a localuse ... as uvalias. It runs on any host, so the next removal of a declaration that Windows-only code still uses is reported without a Windows target installed (on this tree it resolves 655 references to 161 distinct items across 63 files).bun run rust:check-allstays the complete check; this is the part of it that runs in under a second on a released bun.cargo check -p bun_runtime --target x86_64-pc-windows-msvcwithout the declarations reproduces exactly the three E0425 errors above; with them it passes.cargo check --workspacepasses for bothx86_64-pc-windows-msvcandaarch64-pc-windows-msvcwith zero warnings.ipc_host.rs:374: uv_os_getppid,node_cluster_binding.rs:391: uv_translate_sys_error,node_util_binding.rs:75: uv_translate_sys_error) and passes with them (bun bd test test/internal/source-lints/libuv-sys-exports.test.ts).test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts(the pin list added by Remove dead code from libuv_sys, cares_sys, simdutf FFI, test_runner, and C++ bindings #37332) still passes; it does not list either symbol.cargo fmt --check -p bun_libuv_sys, prettier, andtscon the new test file are clean.The other red test in build 96732,
test/js/node/test/parallel/test-http-chunk-problem.json Linux aarch64 (also red on main build 96727), is a separate break and is not addressed here.Background
bun_libuv_sys(src/libuv_sys) is Bun's hand-written Rust FFI surface for libuv, which Bun only uses on Windows.lib.rsis compiled everywhere, but the whole binding modulelibuv.rsis#![cfg(windows)], andlib.rsre-exports it withpub use libuv::*, so callers writebun_libuv_sys::uv_fs_open.bun_sys::windowsre-exports the crate aslibuv, which is why most callers spell itbun_sys::windows::libuvoruse bun_sys::windows::libuv as uv;.uv_translate_sys_errorconverts a Win32/WinSock error code into libuv's negativeUV_E*code.node:clusteruses it on Windows in two places: the shared-handle bind binding (cluster_raw_bind) and the round-robin handle (RoundRobinHandle.ts, through theuvTranslateSysErrorbinding), so a failed bind reaches the worker as the sameUV_E*code Node's cluster protocol carries.uv_os_getppidis libuv's portable parent-pid lookup;process.send()on Windows falls back to it for the pid thatWSADuplicateSocketWneeds when a socket handle is sent over IPC and the channel has not reported the peer pid.cfg(...)attribute removes code from compilation entirely on targets where it does not apply, so rustc on a non-Windows host never resolves paths insidecfg(windows)code. That is what lets a declaration and its only callers disagree without any error on the host that verified the change.test/internal/source-lints/holds tests that only read the source tree (see its README); they run against a released bun in seconds and do not need the build under test.