2010-08-05 42 views
133

Các kịch bản mà một tiến trình nhận được SIGABRT trong C++ là gì? Liệu tín hiệu này luôn đến từ bên trong quá trình hay tín hiệu này có thể được gửi từ quy trình này sang tiến trình khác không?Khi nào thì một quá trình nhận được SIGABRT (tín hiệu 6)?

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

+2

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ý trình xử lý tín hiệu cho SIGABRT để in ra thông tin đó và xóa luồng của nó trước khi trở về. Cách dễ nhất thứ hai là chạy chương trình trong strace. Cách dễ nhất thứ ba là đảm bảo chương trình tạo ra một tệp lõi khi nó gặp sự cố và tìm hiểu thông qua kết xuất lõi. –

Trả lời

134

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

abort() thường được gọi bằng 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 nghiêm trọng bị hỏ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 bộ nhớ heap.

+14

đối với tôi trong hầu hết các trường hợp SIGABRT được gửi bởi 'libc' cố gắng gọi' free() 'trên con trỏ không được khởi tạo/bị hỏng – grandrew

+0

Nếu tôi có một nơi nào đó trong mã, hãy gọi hàm gọi ảo tinh khiết từ bên trong hàm tạo, có thể cũng kết thúc với tín hiệu SIGABRT? Tôi hỏi khi tôi gặp lỗi khi nói rằng tôi có cuộc gọi ảo thuần túy và dòng tiếp theo cho tôi 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

44

Bạn có thể gửi bất kỳ tín hiệu để xử lý bất kỳ bằng cách sử dụng giao diện kill(2):

kill -SIGABRT 30823

30823 là một quá trình dash 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 ra Aborted rõ ràng là cách dash báo cáo SIGABRT.

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

37

SIGABRT thường được sử dụng bởi libc và các thư viện khác để hủy progamm trong trường hợp lỗi nghiêm trọng. Ví dụ, glibc gửi một số SIGABRT trong trường hợp bị phát hiện lỗi kép hoặc các lỗi khác.

Ngoài ra, hầu hết các triển khai "assert" đều sử dụng số SIGABRT trong trường hợp xác nhận không thành công.

Ngoài ra, SIGABRT có thể được gửi từ bất kỳ quy trình nào khác như bất kỳ tín hiệu nào khác. Tất nhiên, quá trình gửi cần phải chạy như cùng một người dùng hoặc gốc.

12

Điều này thường xảy ra khi có sự cố khi cấp phát bộ nhớ.

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

3

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

Xem bài của tôi trên chuyển hướng libc để viết thư cho thiết bị lỗi chuẩn thay vì/dev/tty:

Catching libc error messages, redirecting from /dev/tty

6

Có một nguyên nhân đơn giản trong trường hợp 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 hoặc

thread::join(); 

hoặc

thread::detach(); 
1

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ỉ số tương đương với chiều 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 không có mặt.

2

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

#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 các tập tin cốt lõi, và xác nhận SIGABRT thực sự được gọi là:

gdb aa core 

thấy regs: Mã

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

kiểm tra:

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

:)

Các vấn đề liên quan