• setjmp和longjmp重复使用的问题


    C本身没有异常机制。有时程序执行失败时,系统会发出信号进行处理。最常见的就是发生非法内存访问时报段错误,有时候我们并不希望这时程序就终止退出了,而希望发生这种情况时给出自己的处理过程让程序继续运行下去。当然找到访问错误的原因并改正更加重要,来个捕获处理却不失为一种救火的方法。

    实现的一个思路是使用setjmp/longjmp组合,当捕捉到一个信号时,进入信号捕捉函数,处理后继续执行。然而使用这对组合后,此时当前信号被自动地加到进程的信号屏蔽字中,这阻止了后来产生的这种信号中断该信号处理程序。如果用longjmp跳出信号处理程序,信号屏蔽字不一定被恢复(各个发行版处理策略不同),从而再次执行到这里时我们自定义的处理过程失效。

    举例

    来个非法访问内存的程序。试图访问低地址的内存空间,os是不会允许的

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 
     4 #include <setjmp.h>
     5 #include <signal.h>
     6 jmp_buf Jump_Buffer;
     7 
     8 #define BLOCK "block"
     9 
    10 static void sig_segv(int signo) {
    11         signal(SIGSEGV, sig_segv);
    12         if (signo == SIGSEGV){
    13                 printf("sigsegvvvvvvvv\n");
    14                 longjmp(Jump_Buffer, 1);
    15         }
    16 }
    17 
    18 int fun(){
    19         int addr = 1;
    20         char name[10];
    21         if (signal(SIGSEGV, sig_segv) != sig_segv)
    22                 signal(SIGSEGV, sig_segv);
    23         if(setjmp(Jump_Buffer) != 0){//这里设置后longjmp将跳到这里
    24                 printf("exceptions\n");
    25                 strcpy(name, BLOCK);
    26         }
    27         else{
    28                 strncpy(name, (char*)addr, 10);
    29         }
    30         name[9] = '\0';
    31 
    32         printf("%d,%d,%s\n", sizeof(BLOCK), strlen(BLOCK), name);
    33         return 0;
    34 }
    35 
    36 int main(){
    37         fun();
    38         fun();
    39 
    40         return 0;
    41 }

    预期我们希望执行strncpy出错时能跳到默认的处理过程中,达到C++异常的效果。然而,第二次调用fun()却仍然报段错误,如下

    所幸的是,POSIX.1定义了另一对函数:sigsetjmp和siglongjmp。
    sigsetjmp多了一个参数savemask,如果savemask非0,则sigsetjmp在env中保存进程的当前信号屏蔽字。调用siglongjmp时,如果带非0savemask的sigsetjmp调用已经保存了env,则siglongjmp从其中恢复保存的信号屏蔽字。这就解决了循环中调用setjmp,反复调用longjmp时,仅第一次longjmp生效的问题。

    修改如下

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 
     4 #include <setjmp.h>
     5 #include <signal.h>
     6 jmp_buf Jump_Buffer;
     7 
     8 #define BLOCK "block"
     9 
    10 static void sig_segv(int signo) {
    11         signal(SIGSEGV, sig_segv);
    12         if (signo == SIGSEGV){
    13                 printf("sigsegvvvvvvvv\n");
    14                 siglongjmp(Jump_Buffer, 1);//使用了siglongjmp
    15         }
    16 }
    17 
    18 int fun(){
    19         int addr = 1;
    20         char name[10];
    21         if (signal(SIGSEGV, sig_segv) != sig_segv)
    22                 signal(SIGSEGV, sig_segv);
    23         if(sigsetjmp(Jump_Buffer, 1) != 0){//这里使用sigsetjmp,有第二个参数
    24                 printf("exceptions\n");
    25                 strcpy(name, BLOCK);
    26         }
    27         else{
    28                 strncpy(name, (char*)addr, 10);
    29         }
    30         name[9] = '\0';
    31 
    32         printf("%d,%d,%s\n", sizeof(BLOCK), strlen(BLOCK), name);
    33         return 0;
    34 }
    35 
    36 int main(){
    37         fun();
    38         fun();
    39 
    40         return 0;
    41 }

    执行结果如下

    达到了预期的目标。

  • 相关阅读:
    第四十三课:jQuery插件化
    js模块化开发
    第四十二课:基于CSS的动画引擎
    第四十一课:CSS3 animation详解
    第四十课:CSS3 transition详解
    第三十九课:requestAnimationFrame详解
    几种排序
    图与搜索
    数组
    链表
  • 原文地址:https://www.cnblogs.com/njucslzh/p/2849813.html
Copyright © 2020-2023  润新知