fix(setjmp): restore caller rbx in sigsetjmp mask path
This commit is contained in:
@@ -294,6 +294,30 @@ underscore_forms_test(void)
|
||||
check(r == 9, "_longjmp(env,9) -> _setjmp returned 9");
|
||||
}
|
||||
|
||||
/*
|
||||
* 7. The initial sigsetjmp(env, 1) return must preserve the caller's rbx.
|
||||
* A canary is planted in rbx via inline assembly (declared clobbered, so
|
||||
* the compiler holds nothing else there), sigsetjmp returns normally, and
|
||||
* rbx is read back raw: the SysV AMD64 ABI requires the function to leave
|
||||
* every callee-saved register intact on the ordinary return path, and the
|
||||
* compiler assumes exactly that when allocating registers around the call,
|
||||
* so nothing reloads rbx between the plant and the read.
|
||||
*/
|
||||
static __attribute__((noinline)) void
|
||||
rbx_callee_saved_test(void)
|
||||
{
|
||||
sigjmp_buf env;
|
||||
unsigned long after = 0;
|
||||
int r;
|
||||
|
||||
__asm__ volatile("mov $0x12345678, %%rbx" ::: "rbx");
|
||||
r = sigsetjmp(env, 1);
|
||||
__asm__ volatile("mov %%rbx, %0" : "=r"(after));
|
||||
|
||||
check(r == 0, "sigsetjmp(env,1) initial return is 0 (rbx canary scenario)");
|
||||
check(after == 0x12345678UL, "caller rbx preserved across sigsetjmp(env,1) initial return");
|
||||
}
|
||||
|
||||
/*
|
||||
* Failure scenario (-f): longjmp(env, 0) must make setjmp return 1. Exits 0
|
||||
* only when the coercion behaved exactly as POSIX specifies.
|
||||
@@ -334,6 +358,7 @@ main(int argc, char **argv)
|
||||
fp_state_test();
|
||||
sigmask_test();
|
||||
underscore_forms_test();
|
||||
rbx_callee_saved_test();
|
||||
|
||||
if (failures > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user