Skip to content

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

Closed

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.

Activity

  1. added 2 commits that reference this issue on May 17, 2026
  2. proggeramlug commented on May 17, 2026

    @proggeramlug
    Contributor

    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 in crates/perry-runtime/src/ffi/setjmp.rs with darwin/Linux signature (*mut c_int) -> c_int; clashing_extern_declarations warning gone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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