You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix: _setjmp redeclared with mismatched signatures in gc.rs vs promise.rs (potential UB) #856
cargo build --release flags a clashing extern declaration for _setjmp:
warning: `setjmp` redeclares `_setjmp` with a different signature
--> crates/perry-runtime/src/promise.rs:956:9
|
956 | #[link_name = "_setjmp"]
| ^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
|
::: crates/perry-runtime/src/gc.rs:1860:13
|
1860 | #[link_name = "_setjmp"]
| ------------------------ `_setjmp` previously declared here
|
= note: expected `unsafe extern "C" fn(*mut u64) -> i32`
found `unsafe extern "C" fn(*mut i32) -> i32`
= note: `#[warn(clashing_extern_declarations)]` on by default
Why this matters
Both sites link to the same C symbol (_setjmp) with different parameter types (*mut u64 vs *mut i32). If they happen to be called with buffers sized for one but the runtime layout matches the other, this is undefined behavior — buffer corruption is silent and platform-dependent. The fact that it currently appears to work is luck of the macOS / aarch64 ABI, not safety.
Investigation needed
What does _setjmp actually take on macOS / Linux?
On darwin, jmp_buf is int[_JBLEN] — i.e. effectively *mut c_int.
On glibc Linux, the layout is also int[] though _JBLEN differs.
What does each call site actually use the buffer for?
gc.rs uses it as a register-snapshot blob (u64[]).
promise.rs uses it for an unwind context (i32[]).
Are either of them allocating the wrong-sized buffer?
Proposed fix shape
Introduce a single extern "C" block (e.g. runtime::ffi::setjmp or as a small shared module) with the correct libc-matching signature. Have both gc.rs and promise.rs import that one declaration. Remove the duplicated #[link_name] declarations.
If the two sites genuinely need to view the same buffer through different lenses, cast the pointer at the call site rather than redeclaring the extern.
Context
Spotted by the warning-cleanup PR (chore: reduce compile warnings 325 → 125). Kept out of that PR because it requires investigation of libc layouts and the runtime's stack-unwinding contract.
Activity
fix(runtime): #856 — single canonical _setjmp extern shared by gc.rs …
fix(runtime): #856 — single canonical _setjmp extern shared by gc.rs …
proggeramlug commentedon May 17, 2026
Closed by PR #914 (
fix(runtime): #856 — single canonical _setjmp extern shared by gc.rs + promise.rs) merged 2026-05-17. Single shared FFI declaration incrates/perry-runtime/src/ffi/setjmp.rswith darwin/Linux signature(*mut c_int) -> c_int; clashing_extern_declarations warning gone.