Since you're invoking undefined behaviour, it's OK for one compiler to crash and another to appear to work. Both are correct - that's the beauty of undefined behaviour.
The trouble is that a saved context - the jmp_buf
- only remains valid as long as the function that called setjmp()
to set it has not returned.
The C99 standard (no longer the current standard, but this wording is unlikely to have changed significantly) says:
§7.13.2.1 The longjmp
function
The longjmp
function restores the environment saved by the most recent invocation of
the setjmp
macro in the same invocation of the program with the corresponding
jmp_buf
argument. If there has been no such invocation, or if the function containing
the invocation of the setjmp
macro has terminated execution208) in the interim, or if the
invocation of the setjmp
macro was within the scope of an identifier with variably
modified type and execution has left that scope in the interim, the behavior is undefined.
208) For example, by executing a return
statement or because another longjmp
call has caused a
transfer to a setjmp
invocation in a function earlier in the set of nested calls.
Your code is exiting from action_1()
almost immediately, rendering the jmp_buf
saved by setjmp()
worthless.
I created this little demonstration of setjmp()
and longjmp()
a couple of years ago. It may help you.
/*
@(#)File: $RCSfile: setjmp.c,v $
@(#)Version: $Revision: 1.1 $
@(#)Last changed: $Date: 2009/10/01 16:41:04 $
@(#)Purpose: Demonstrate setjmp() and longjmp()
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 2009
*/
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
static jmp_buf target_location;
static void do_something(void)
{
static int counter = 0;
if (++counter % 10 == 0)
printf("---- doing something: %3d\n", counter);
if (counter % 1000 == 0)
{
printf("||-- doing_something: calling longjmp() with value -1\n");
longjmp(target_location, -1);
}
}
static void do_something_else(int i, int j)
{
printf("-->> do_something_else: (%d,%d)\n", i, j);
do_something();
if (i > 2 && j > 2 && j % i == 2)
{
printf("||-- do_something_else: calling longjmp() with value %d\n", (i + j) % 100);
longjmp(target_location, (i + j) % 100);
}
printf("<<-- do_something_else: (%d,%d)\n", i, j);
}
static void doing_stuff(void)
{
int i;
printf("-->> doing_stuff()\n");
for (i = rand() % 15; i < 30; i++)
{
int j;
do_something();
for (j = rand() % 10; j < 20; j++)
{
do_something_else(i, j);
}
}
printf("<<-- doing_stuff()\n");
}
static void manage_setjmp(void)
{
printf("-->> manage_setjmp()\n");
switch (setjmp(target_location))
{
case 0:
/* Initial return - get on with doing stuff */
doing_stuff();
break;
case -1:
/* Error return - terminate */
printf("<<-- manage_setjmp() - error return from setjmp()\n");
return;
default:
/* NB: not officially possible to assign the return from setjmp() */
printf("---- manage_setjmp() - non-error return from setjmp()\n");
doing_stuff();
break;
}
printf("<<-- manage_setjmp()\n");
}
int main(void)
{
printf("-->> main()\n");
manage_setjmp();
printf("<<-- main()\n");
return(0);
}