volatile in sigsetjmp and siglongjmp
conclusion
In postgresql, the error handling methods pg_try() + elog() + pg_catch()
is implemented through sigsetjmp
and siglongjmp
. But the variables changed in pg_try()
and used in pg_catch()
must be declared as volatile
. The reasons are below:
reason
- The sigsetjmp call must store all the register value and the siglongjmp restore the registers from it. It’s very reasonable in the view of asm code.
- If a variable is not declared as volatile, the assignment operation of it in
pg_try()
may only changes the variable in the register. And after jumping by thesiglongjmp
call, the value of variable is changed back to the point ofsigsetjmp
, which means the changes inpg_try()
lost
example
Let’s consider an example:
void example_function() {
int counter = 0; // Should be "volatile int counter = 0;"
PG_TRY();
{
counter = 42;
// Some operation that might throw an error
perform_risky_operation();
}
PG_CATCH();
{
// We expect counter to be 42 here
elog(WARNING, "Operation failed, counter value: %d", counter);
}
PG_END_TRY();
}
Without volatile
, the compiler might:
- Keep
counter
in a register - Never actually write the value 42 back to memory
- When the error occurs and
PG_CATCH
executes aftersiglongjmp
, the value ofcounter
might not be 42 as expected
With volatile
, the compiler is forced to:
- Actually write to memory whenever
counter
is modified - Read from memory whenever
counter
is accessed - Not reorder or optimize away these memory operations
This ensures that after the non-local jump, the variable has the expected value.
-Wclobbered
is useless
FROM https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
`-Wclobbered`[](https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wclobbered)
Warn for variables that might be changed by `longjmp` or `vfork`. This warning is also enabled by -Wextra.
FROM pg source
* Note: if a local variable of the function containing PG_TRY is modified
* in the PG_TRY section and used in the PG_CATCH section, that variable
* must be declared "volatile" for POSIX compliance. This is not mere
* pedantry; we have seen bugs from compilers improperly optimizing code
* away when such a variable was not marked. Beware that gcc's -Wclobbered
* warnings are just about entirely useless for catching such oversights.