180 likes | 472 Vues
Setjmp, Longjmp. int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val);. Useful functions for dealing with errors and interrupts setjmp saves its environment (i.e. registers) in env for later use by longjmp
E N D
Setjmp, Longjmp int setjmp(jmp_buf env); void longjmp(jmp_buf env, int val); • Useful functions for dealing with errors and interrupts • setjmp saves its environment (i.e. registers) in env for later use by longjmp • After longjmp completes, program starts after call to setjmp, as if setjmp had returned val.
Setjmp, Longjmp: Example 1 Consider writing a project that will fail if it ever segfaults. Instead just gracefully restart it. How would you go about doing this? Catch the SIGSEGV, and use setjmp/longjmp to jump back to the beginning.
Setjmp, Longjmp: Example 1 con’t scanf("%d", &opt); switch(opt) { case 1: /* FindPerson(); */ printf("\n Finding a person\n"); break; case 2: /* AddPerson(); */ printf("\n Adding a person\n"); break; case 3: /* DeletePerson(); */ printf("\n Deleting a person\n"); break; case 4: exit(0); default: printf("\n Invalid Menu option\n"); break; } } /* end while loop */ return; } #include <stdio.h> int main() { int opt; while(1) { printf("Directory Main Menu\n"); printf("-------------------------------\n"); printf("1. Find Person\n"); printf("2. Add Person\n"); printf("3. Delete Person\n"); printf("4. Exit\n"); printf("Enter your menu option: ");
Setjmp, Longjmp: Example 1 con’t #include <setjmp.h> #include <signal.h> #include <stdio.h> jmp_buf Env; void handler(int sig) { /* Can do clean up here */ longjmp(Env, 1); } int main() { int opt; signal(SIGSEGV, handler); if(setjmp(Env) != 0) { printf("\n\n Returning to Main Menu \n"); } while(1) { printf("Directory Main Menu\n"); printf("-------------------------------\n"); printf("1. Find Person\n"); printf("2. Add Person\n"); printf("3. Delete Person\n"); printf("4. Exit\n"); printf("Enter your menu option: "); scanf("%d", &opt); switch(opt) { case 1: /* FindPerson(); */ printf("\n Finding a person\n"); break; case 2: /* AddPerson(); */ printf("\n Adding a person\n"); break; case 3: /* DeletePerson(); */ printf("\n Deleting a person\n"); break; case 4: exit(0); default: printf("\n Invalid Menu option\n"); break; } } /* end while loop */ return; }
Setjmp, Longjmp: Example 2 What is the output of the following program -- sj.c? #include <setjmp.h> #include <stdio.h> int a(char *s, jmp_buf env) { int i; i = setjmp(env); printf("Setjmp returned -- %d\n", i); printf("s = %s\n", s); return i; } int b(int i, jmp_buf env) { printf("In b: i = %d, Calling longjmp\n", i); longjmp(env, i); } int main() { jmp_buf env; if(a("Bob", env) != 0) exit(0); b(3,env); return 0; }
Setjmp, Longjmp: Example 2 con’t Output: ??? UNIX> sj Setjmp returned -- 0 s = Bob In b: I = 3, Calling longjmp Setjmp returned -- 3 s = Bob UNIX> sj Setjmp returned -- 0 s = Bob In b: I = 3, Calling longjmp Setjmp returned -- 3 Segmentation Fault
Setjmp, Longjmp: Example 2 con’t Let’s take a look at the stack to see why we’re segfaulting. old %ebp %ebp First, main( ) looks like this. %eip --> in main env[8] …. env[0] %esp
Setjmp, Longjmp: Example 2 con’t old %ebp env[8] Then main( ) calls a( ). %eip --> in a …. env[0] s = “Bob” Rtn Addr %ebp old %ebp i %esp
Setjmp, Longjmp: Example 2 con’t old %ebp Then main( ) calls a( ). %eip --> in a Then a( ) calls setjmp( ). This saves the current state of the registers. env[8] …. env[0] s = “Bob” Rtn Addr %ebp old %ebp i %esp
Setjmp, Longjmp: Example 2 con’t old %ebp env[8] …. Returned to main( ), and main( ) calls b( ). %eip --> in b env[0] i = 3 Rtn Addr %ebp old %ebp i %esp
Setjmp, Longjmp: Example 2 con’t old %ebp env[8] longjmp( ) is called, and the regs are restored to their values of when a( ) was called. %eip --> in a …. env[0] s =?? 3 Rtn Addr %ebp old %ebp i %esp Why the segfault?? --> the stack is in a bad state. a( ) expects a (char *) instead of the int value 3. This a common bug with setjmp/longjmp ---> You CANNOT return from a function that calls setjmp!