Skip to content

fix: _setjmp redeclared with mismatched signatures in gc.rs vs promise.rs (potential UB) #856

Description

@TheHypnoo

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

  1. 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.
  2. 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[]).
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions