setjmp和longjmp重複使用的問題

來源:互聯網
上載者:User

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);//使用了siglongjmp15         }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 }

執行結果如下

達到了預期的目標。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.