...
Code Block | ||||
---|---|---|---|---|
| ||||
jmp_buf buf; unsigned char b[] = {0xe5, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}; int main(void) { setup(); do_stuff(); return 0; } void setup(void) { f(); } void f(void) { g(); } #include <setjmp.h> #include <stdio.h> #include <stdlib.h> static jmp_buf buf; static void bad(void); static void g(void) { if (setjmp(buf) == 0) { printf("setjmp() invoked\n"); } else { printf("longjmp() invoked\n"); } } static void do_stufff(void) { char a[8]; memcpy(a, b, 8)g(); } static void setup(void) { f(); } void do_stuff(void) { void (*b)(void) = bad; /* ... */ longjmp(buf, 1); } static void bad(void) { printf("Should not be called!\n"); exit(1); } int main(void) { setup(); do_stuff(); } |
Implementation Details
Compiled at -O0 for x86-64 using GCC 4.1.2 or Clang on Linux, the preceding the preceding example outputs the following when run:
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <setjmp.h> #include <stdio.h> #include <stdlib.h> static jmp_buf buf; unsignedstatic char b[] = {0xe5, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}void bad(void); intvoid maindo_stuff(void) { ifvoid (setjmp*b)(bufvoid) == 0) { printf("setjmp() invoked\n"); } else bad; /* ... */ longjmp(buf, 1); } static void bad(void) { printf("longjmp() invokedShould not be called!\n"); } do_stuff(); return 0exit(1); } voidint do_stuffmain(void) { char a[8]; memcpy(a, b, 8); /* ... */ longjmp(buf, 1); } void bad(void)if (setjmp(buf) == 0) { printf("setjmp() invoked\n"); } else { printf("Should not be called!longjmp() invoked\n"); } exitdo_stuff(1); } |
There is no risk of overwriting a return address because the stack frame of main()
(the function that invoked setjmp()
) is still on the stack; so when do_stuff()
is invoked, the two stack frames will not overlap.
...