Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(kernel): prevent setjmp/longjmp miscompilations through call_with_setjmp #195

Merged
merged 5 commits into from
Dec 29, 2024

Conversation

JonasKruckenberg
Copy link
Owner

@JonasKruckenberg JonasKruckenberg commented Dec 28, 2024

This PR adds a safer wrapper for setjmp called call_with_setjmp that helps to prevent LLVM miscompilations such as happened here where LLVM emitted a store immediate 1 instead of a load-add-store sequence for this code snippet:

let mut c = 0;
let mut buf = JumpBuf::new();

let r = setjmp(ptr::from_mut(&mut buf));
c += 1; // on opt-lvl >=1 this becomes a store immediate 1 instead of a load-add-store
        // because LLVM rightly assumes that this point will only be reached once per frame
if r == 0 {
    assert_eq!(c, 1);
    longjmp(ptr::from_mut(&mut buf), 1234567);
}
assert_eq!(c, 2);
assert_eq!(r, 1234567);

(see on godbolt here)

If you force c into a different stack frame or into a static things are fine btw if you were curious (see the setjmp_longjmp_simple test for more).

The proper solution though - documented here and adapted into a crate https://github.com/pnkfelix/cee-scape - is to use inline assembly and mark all registers as clobbered along with preventing accidental misuse of the JmpBuf in invalid contexts.

@JonasKruckenberg JonasKruckenberg merged commit e285044 into main Dec 29, 2024
16 checks passed
@JonasKruckenberg JonasKruckenberg deleted the jonas/feat/call_with_setjmp branch December 29, 2024 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant