michael michael - 1 month ago 4x
C Question

Safe usage of longjmp/setjmp with volatile

I consider to use a TRY/CATCH macro based on setjmp/longjmp for error handling. Otherwise some of my quite structued functions will be blown up by ugly if statements and loop flags.

The code is like this example:

int trycatchtest(int i)
int result = 0;
volatile int error = 100;
volatile uint32_t *var = NULL;
error = 0;
var = os_malloc(4);
*var = 11;
if (i) THROW( i );
result = *var;
return result;

THROW is in fact the macro

#define TRY do { jmp_buf buf; switch( setjmp(buf) ) { case 0: while(1) {
#define FINALLY break; } default: {
#define END break; } } } while(0)
#define THROW(x) longjmp(buf, x)

The Problem:

When the exception is thrown (e.g. i=1) the pointer var is reset to NULL, although I used the volatile keyword, which should avoid using a register for it. From the debugger I see that is is still within a register and not in memory.

Did I make a mistake ?


I changed declaration of var into

uint32_t * volatile var = NULL;

This works ;-)

I do not really understand what is the difference:

volatile uint32_t * var = NULL;

means, that the VALUE is volatile, whereas the former declararation makes the pointer volatile?


u32 *volatile var makes the pointer volatile, while volatile u32 *var tells the compiler that the data at that address is volatile. So since the pointer is not volatile in the latter example, I wouldn't be surprised if your compiler optimized away the default case completely to something like result = NULL;.

It probably doesn't expect the setjmp wizardry, and these are notorious for being even "more spaghetti than goto".