使用signal、setjmp、longjmp进行Linux/Android C异常处理
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <signal.h> 4 #include <setjmp.h> 5 jmp_buf sigsegv_buf; 6 7 8 void sigsegv_callback(int sig_num){ 9 printf("recieve a segment fault signal! [%d]\n", sig_num); 10 longjmp(sigsegv_buf, 1); 11 return; 12 } 13 void vulfunc(){ 14 char dest[4]; 15 printf("into vulfunc\n"); 16 strcpy(dest, "deadbeefdeadbeefdeadbeefdeadbeef"); 17 printf("%s\n", dest); 18 return; 19 } 20 21 int main(){ 22 bsd_signal(SIGSEGV, sigsegv_callback); 23 int res; 24 res = setjmp(sigsegv_buf); 25 if(res==0){ 26 vulfunc(); 27 }else if(res==1){ 28 printf("recovered from segment fault!\n"); 29 } 30 printf("end\n"); 31 if(res!=0){ 32 exit(0); 33 } 34 return 0; 35 }
一个缓冲区溢出函数,导致segment fault 出发异常后的捕获和处理。
- main函数中利用signal/bsd_signal函数注册异常处理函数 sigsegv_callback
- 用setjmp设置程序恢复点(保存寄存器状态)
- 调用vulfunc,发生溢出,导致segment fault
- 执行到sigsegv_callback
- 在sigsegv_callback中使用longjmp从保存的状态中恢复程序到setjmp的下一条指令,设置setjmp的返回值为非0
- setjmp返回的是longjmp中设置的非0值,从而跳转setjmp后面的另一分支。
在Android(native executable file和Java+jni )测试。
亦可参考:http://www.csl.mtu.edu/cs4411.ck/www/NOTES/non-local-goto/sig-1.html