Khi nào một quá trình có được SIGABRT (tín hiệu 6)?


202

Các tình huống trong đó một quá trình có SIGABRT trong C ++ là gì? Có phải tín hiệu này luôn đến từ trong quy trình hay tín hiệu này có thể được gửi từ quy trình này sang quy trình khác không?

Có cách nào để xác định quá trình nào đang gửi tín hiệu này không?


3
Có một vài cách. Cách dễ nhất, nếu bạn đã viết chương trình, là đăng ký một trình xử lý tín hiệu cho SIGABRT để in ra thông tin đó và xóa các luồng của nó trước khi quay lại. Cách dễ nhất thứ hai là chạy chương trình trong phạm vi. Cách dễ nhất thứ ba là đảm bảo chương trình tạo tệp lõi khi nó gặp sự cố và tìm hiểu thông qua kết xuất lõi.
Bắn Parthian

Câu trả lời:


194

abort()gửi quá trình gọi SIGABRTtín hiệu, đây là cách abort()cơ bản hoạt động.

abort()thường được gọi bởi các chức năng thư viện phát hiện lỗi nội bộ hoặc một số ràng buộc bị hỏng nghiêm trọng. Ví dụ malloc()sẽ gọi abort()nếu cấu trúc bên trong của nó bị hỏng do tràn heap.


27
đối với tôi trong hầu hết các trường hợp, SIGABRT đã được gửi bằng cách libccố gắng gọi free()một con trỏ không được khởi tạo / bị hỏng
ghi vào

Nếu tôi có một nơi nào đó trong mã, bị chôn vùi gọi hàm ảo thuần từ bên trong hàm tạo, điều đó cũng có thể kết thúc với tín hiệu SIGABRT? Tôi đang hỏi khi tôi thấy một lỗi thông báo rằng tôi có một cuộc gọi ảo thuần túy và dòng tiếp theo cung cấp cho tôi một thông báo SIGABRT và ứng dụng bị treo hoặc bị đóng bởi hệ điều hành. Cảm ơn.
Hrvoje

2
Trên MacOS, chúng tôi đã có SIGABRT để mở khoảng 1000 tệp xử lý mà không đóng chúng. Thay vì chế giễu, các thử nghiệm của chúng tôi đã trừu tượng hóa tệp với loại trình đọc chung chung hơn, không có Close()phương thức, vì vậy nó đã bị lãng quên. Có bảo hiểm tuyệt vời mặc dù. : xe đẩy:
Zyl

51

SIGABRTthường được libc và các thư viện khác sử dụng để hủy bỏ chương trình trong trường hợp có lỗi nghiêm trọng. Ví dụ, glibc gửi một SIGABRTtrong trường hợp có phát hiện tham nhũng đống đúp miễn phí hoặc khác.

Ngoài ra, hầu hết các asserttriển khai sử dụng SIGABRTtrong trường hợp khẳng định không thành công.

Hơn nữa, SIGABRTcó thể được gửi từ bất kỳ quá trình khác như bất kỳ tín hiệu khác. Tất nhiên, quá trình gửi cần phải chạy như người dùng hoặc root.


49

Bạn có thể gửi bất kỳ tín hiệu cho bất kỳ quá trình bằng cách sử dụng kill(2)giao diện:

kill -SIGABRT 30823

30823 là một dashquá trình tôi bắt đầu, vì vậy tôi có thể dễ dàng tìm thấy quá trình tôi muốn giết.

$ /bin/dash
$ Aborted

Đầu Abortedra rõ ràng là cách dashbáo cáo SIGABRT.

Nó có thể được gửi trực tiếp đến bất kỳ quá trình sử dụng kill(2), hoặc một quá trình có thể gửi tín hiệu cho chính nó thông qua assert(3), abort(3)hoặc raise(3).


17

Nó thường xảy ra khi có vấn đề với việc cấp phát bộ nhớ.

Nó xảy ra với tôi khi chương trình của tôi đang cố gắng phân bổ một mảng với kích thước âm.


14

Có một nguyên nhân đơn giản khác trong trường hợp của c ++.

std::thread::~thread{
    if((joinable ())
        std::terminate ();
}

tức là phạm vi của chủ đề đã kết thúc nhưng bạn quên gọi

thread::join();

hoặc là

thread::detach();

7

GNU libc sẽ in ra thông tin /dev/ttyliên quan đến một số điều kiện gây tử vong trước khi nó gọi abort()(sau đó kích hoạt SIGABRT), nhưng nếu bạn đang chạy chương trình của mình như một dịch vụ hoặc không phải trong một cửa sổ đầu cuối thực sự, những thông báo này có thể bị mất, bởi vì không có tty để hiển thị các tin nhắn.

Xem bài đăng của tôi về chuyển hướng libc để ghi vào stderr thay vì / dev / tty:

Bắt các thông báo lỗi libc, chuyển hướng từ / dev / tty


4

Một trường hợp khi quá trình nhận SIGABRT từ chính nó: Hrvoje đã đề cập về một ảo thuần bị chôn vùi được gọi từ ctor tạo ra một lệnh hủy bỏ, tôi đã tạo lại một ví dụ cho điều này. Ở đây khi d được xây dựng, đầu tiên nó gọi lớp cơ sở A ctor của nó và truyền con trỏ vào chính nó. một ctor gọi phương thức ảo thuần túy trước khi bảng được điền với con trỏ hợp lệ, vì d chưa được xây dựng.

#include<iostream>
using namespace std;
class A {
public:
 A(A *pa){pa->f();}
 virtual void f()=0;
};
class D : public A {
public:
 D():A(this){}
 virtual void f() {cout<<"D::f\n";}
};
int main(){
 D d;
 A *pa = &d;
 pa->f();
 return 0;
}

biên dịch: g ++ -o aa aa.cpp

ulimit -c không giới hạn

chạy: ./aa

pure virtual method called
terminate called without an active exception
Aborted (core dumped)

bây giờ cho phép nhanh chóng xem tệp cốt lõi và xác thực rằng SIGABRT thực sự được gọi là:

gdb aa core

xem regs:

i r
rdx            0x6      6
rsi            0x69a    1690
rdi            0x69a    1690
rip            0x7feae3170c37

kiểm tra mã:

disas 0x7feae3170c37

mov    $0xea,%eax  = 234  <- this is the kill syscall, sends signal to process
syscall   <-----

http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

234 sys_tgkill pid_t tgid pid_t pid int sig = 6 = SIGABRT

:)


2

Trong trường hợp của tôi, đó là do một đầu vào trong một mảng tại một chỉ mục bằng với độ dài của mảng.

string x[5];

for(int i=1; i<=5; i++){

    cin>>x[i];

}

x [5] đang được truy cập mà không có.


1

Như "@sarnold", đã chỉ ra một cách khéo léo, bất kỳ quy trình nào cũng có thể gửi tín hiệu đến bất kỳ quy trình nào khác, do đó, một quy trình có thể gửi SIGABORT đến quy trình khác và trong trường hợp đó, quá trình nhận không thể phân biệt được liệu có phải do điều chỉnh của chính nó không bộ nhớ vv, hoặc ai đó có "unicastly", gửi cho nó.

Trong một trong những hệ thống tôi đã làm việc, có một máy dò bế tắc thực sự phát hiện xem liệu quá trình có thoát ra khỏi một số nhiệm vụ bằng cách cho nhịp tim hay không. Nếu không, nó tuyên bố quá trình ở trạng thái bế tắc và gửi SIGABORT cho nó.

Tôi chỉ muốn chia sẻ triển vọng này với tham khảo cho câu hỏi.


0

Tôi sẽ đưa ra câu trả lời của mình từ góc độ lập trình cạnh tranh (cp) , nhưng nó cũng áp dụng cho các lĩnh vực khác.

Nhiều lần trong khi làm cp, các ràng buộc là khá lớn.

Ví dụ : Tôi đã có một câu hỏi với một biến N, M, Qnhư vậy 1 ≤ N, M, Q < 10^5.

Sai lầm tôi đã làm là tôi tuyên bố một 2D nguyên mảng có kích thước 10000 x 10000trong C++và phải vật lộn với các SIGABRTlỗi ở Codechef trong gần 2 ngày.

Bây giờ, nếu chúng ta tính toán:

Kích thước điển hình của một số nguyên: 4 byte

Số ô trong mảng của chúng tôi: 10000 x 10000

Tổng kích thước (tính bằng byte): 400000000 byte = 4 * 10 ^ 8 400 MB

Các giải pháp của bạn cho những câu hỏi như vậy sẽ hoạt động trên PC của bạn (không phải lúc nào cũng vậy) vì nó có thể đủ khả năng cho kích thước này.

Nhưng tài nguyên tại các trang web mã hóa (thẩm phán trực tuyến) bị giới hạn ở vài KB.

Do đó, SIGABRTlỗi và các lỗi khác như vậy.

Phần kết luận:

Trong các câu hỏi như vậy, chúng ta không nên khai báo một mảng hoặc vectơ hoặc bất kỳ DS nào khác có kích thước này, nhưng nhiệm vụ của chúng ta là làm cho thuật toán của chúng ta hiệu quả đến mức nó hoạt động mà không có chúng (DS) hoặc có ít bộ nhớ hơn.

PS : Có thể có những lý do khác cho lỗi này; ở trên là một trong số họ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.