2012-04-18 74 views
23

Tôi có một ứng dụng mà tôi sử dụng để bắt bất kỳ lỗi phân đoạn nào hoặc ctrl-c. Sử dụng mã bên dưới, tôi có thể bắt lỗi phân đoạn nhưng trình xử lý đang được gọi đi lặp lại. Làm thế nào tôi có thể ngăn chặn chúng. Để biết thông tin của bạn, tôi không muốn thoát khỏi đơn đăng ký của mình. Tôi chỉ có thể chăm sóc để giải phóng tất cả các bộ đệm bị hỏng.Xử lý lỗi phân đoạn

Có thể không?

void SignalInit(void) 
{ 

struct sigaction sigIntHandler; 

sigIntHandler.sa_handler = mysighandler; 
sigemptyset(&sigIntHandler.sa_mask); 
sigIntHandler.sa_flags = 0; 
sigaction(SIGINT, &sigIntHandler, NULL); 
sigaction(SIGSEGV, &sigIntHandler, NULL); 

} 

và trình xử lý diễn ra như thế này.

void mysighandler() 
{ 
MyfreeBuffers(); /*related to my applciation*/ 
} 

Đây là tín hiệu lỗi phân đoạn, trình xử lý được gọi nhiều lần và MyfreeBuffers() cho tôi lỗi giải phóng bộ nhớ đã giải phóng. Tôi chỉ muốn miễn phí một lần nhưng vẫn không muốn thoát khỏi ứng dụng.

Vui lòng trợ giúp.

Trả lời

28

Hành động mặc định cho những thứ như SIGSEGV là chấm dứt quy trình của bạn nhưng vì bạn đã cài đặt trình xử lý cho nó, nó sẽ gọi trình xử lý của bạn ghi đè hành vi mặc định. Nhưng vấn đề là lệnh segfaulting có thể được thử lại sau khi handler của bạn kết thúc và nếu bạn chưa thực hiện các biện pháp để sửa lỗi seg đầu tiên, lệnh retried sẽ lại lỗi và nó cứ tiếp diễn.

chỗ Vì vậy, đầu tiên hướng dẫn dẫn đến SIGSEGV và cố gắng sửa chữa nó (bạn có thể gọi một cái gì đó giống như backtrace() trong xử lý và xem cho chính mình những gì đã xảy ra)

Ngoài ra, các tiêu chuẩn POSIX nói rằng,

hành vi của một quá trình là undefined sau nó sẽ trả về bình thường từ một hàm tín hiệu bắt cho một [XSI] SIGBUS, SIGFPE, SIGILL, hoặc tín hiệu SIGSEGV mà không được tạo ra bởi kill(), [RTS] sigqueue(), hoặc tăng().

Vì vậy, điều lý tưởng cần làm là sửa chữa segfault của bạn ngay từ đầu. Handler cho segfault không có nghĩa là bỏ qua các điều kiện lỗi tiềm ẩn

Vì vậy, đề nghị tốt nhất là be- Đừng bắt SIGSEGV. Hãy để nó đổ lõi. Phân tích cốt lõi. Sửa lỗi tham chiếu bộ nhớ không hợp lệ và ở đó bạn đi!

0

Bạn cũng có thể đặt biến trạng thái và chỉ bộ nhớ trống nếu không được đặt. Trình xử lý tín hiệu sẽ được gọi là mọi lúc, bạn không thể kiểm soát AFAIK đó.

9

Nếu SIGSEGV cháy một lần nữa, kết luận rõ ràng là các cuộc gọi đến MyfreeBuffers();không cố định các vấn đề tiềm ẩn (và nếu hàm thực sự chỉ free() một số cấp phát bộ nhớ, tôi không chắc chắn lý do tại sao bạn sẽ nghĩ nó sẽ).

Khoảng một lần, SIGSEGV sẽ kích hoạt khi một nỗ lực được thực hiện để truy cập vào địa chỉ bộ nhớ không thể truy cập. Nếu bạn không thoát khỏi ứng dụng, bạn cần phải làm cho địa chỉ bộ nhớ đó có thể truy cập được hoặc thay đổi đường dẫn thực hiện bằng longjmp().

6

Bạn không nên cố gắng tiếp tục sau SIG_SEGV. Về cơ bản nó có nghĩa là môi trường của ứng dụng của bạn bị hỏng theo một cách nào đó. Nó có thể là bạn đã chỉ dereferenced một con trỏ null, hoặc nó có thể là một số lỗi đã gây ra chương trình của bạn để làm hỏng stack của nó hoặc heap hoặc một số biến con trỏ, bạn chỉ không biết. chỉ điều an toàn cần làm là chấm dứt chương trình.

Hoàn toàn hợp pháp để xử lý control-C. Rất nhiều ứng dụng làm điều đó, nhưng bạn phải thực sự cẩn thận chính xác những gì bạn làm trong trình xử lý tín hiệu của mình. Bạn không thể gọi bất kỳ chức năng nào không phải là người tham gia lại. Vì vậy, điều đó có nghĩa là nếu bạn MyFreeBuffers() gọi hàm stdlib free(), có thể bạn đã bị hỏng. Nếu người dùng truy cập control-C trong khi chương trình ở giữa malloc() hoặc free() và do đó, bằng cách thao tác các cấu trúc dữ liệu mà họ sử dụng để theo dõi phân bổ heap, bạn gần như chắc chắn sẽ làm hỏng heap nếu bạn gọi malloc() hoặc free() trong tín hiệu xử lý.

Về điều an toàn duy nhất bạn có thể thực hiện trong bộ xử lý tín hiệu, hãy đặt cờ để nói rằng bạn đã thu được tín hiệu. Sau đó, ứng dụng của bạn có thể thăm dò ý kiến ​​cờ trong khoảng thời gian để quyết định xem nó có cần thực hiện một số hành động hay không.

0

Tôi có thể xem tại trường hợp khôi phục từ SIG_SEGV, nếu sự kiện xử lý của bạn trong vòng lặp và một trong các sự kiện này gây ra Vi phạm phân đoạn thì bạn chỉ muốn bỏ qua sự kiện này, tiếp tục xử lý các sự kiện còn lại. Trong mắt tôi SIG_SEGV tương tự như NullPointerException trong Java. Có, tiểu bang sẽ không nhất quán và không rõ sau một trong hai trường hợp này, tuy nhiên trong một số trường hợp, bạn muốn xử lý tình huống và tiếp tục. Ví dụ trong giao dịch Algo, bạn sẽ tạm dừng việc thực hiện một lệnh và cho phép một nhà giao dịch tự tiếp quản, với việc phá vỡ toàn bộ hệ thống và hủy hoại tất cả các lệnh khác.

8

Tôi hoàn toàn không đồng ý với tuyên bố "Không bắt được SIGSEGV".

Đó là một cách khá tốt để xử lý các điều kiện không mong muốn. Và đó là sạch hơn nhiều để đối phó với NULL con trỏ (như được đưa ra bởi thất bại malloc) với cơ chế tín hiệu liên quan đến setjmp/longjmp, hơn là phân phối quản lý tình trạng lỗi tất cả cùng mã của bạn.

Lưu ý tuy nhiên nếu bạn sử dụng '' sigaction '' trên SEGV, bạn phải quên nói SA_NODEFER trong sa_flags - hoặc tìm một cách khác để đối phó với thực tế SEGV sẽ kích hoạt điều khiển của bạn chỉ một lần.

#include <setjmp.h> 
#include <signal.h> 
#include <stdio.h> 
#include <string.h> 

static void do_segv() 
{ 
    int *segv; 

    segv = 0; /* malloc(a_huge_amount); */ 

    *segv = 1; 
} 

sigjmp_buf point; 

static void handler(int sig, siginfo_t *dont_care, void *dont_care_either) 
{ 
    longjmp(point, 1); 
} 

int main() 
{ 
    struct sigaction sa; 

    memset(&sa, 0, sizeof(sigaction)); 
    sigemptyset(&sa.sa_mask); 

    sa.sa_flags  = SA_NODEFER; 
    sa.sa_sigaction = handler; 

    sigaction(SIGSEGV, &sa, NULL); /* ignore whether it works or not */ 

    if (setjmp(point) == 0) 
    do_segv(); 

    else 
    fprintf(stderr, "rather unexpected error\n"); 

    return 0; 
} 
+0

Đây là giải pháp tốt. Tôi đã không đặc biệt thích "để cho nó sụp đổ và sau đó phân tích các bãi chứa lõi." – dturvene