กระบวนการจะได้รับ SIGABRT (สัญญาณ 6) เมื่อใด


202

สถานการณ์ใดบ้างที่กระบวนการรับ SIGABRT ใน C ++ สัญญาณนี้มาจากภายในกระบวนการเสมอหรือสามารถส่งสัญญาณนี้จากกระบวนการหนึ่งไปสู่กระบวนการอื่นได้หรือไม่?

มีวิธีการระบุกระบวนการที่กำลังส่งสัญญาณนี้หรือไม่?


3
มีสองวิธี วิธีที่ง่ายที่สุดถ้าคุณเขียนโปรแกรมคือการลงทะเบียนตัวจัดการสัญญาณสำหรับ SIGABRT ที่พิมพ์ข้อมูลนั้นและล้างกระแสข้อมูลก่อนที่จะส่งคืน วิธีที่ง่ายที่สุดที่สองคือการเรียกใช้โปรแกรมภายใน strace วิธีที่ง่ายที่สุดลำดับที่สามคือตรวจสอบให้แน่ใจว่าโปรแกรมสร้างไฟล์หลักเมื่อเกิดปัญหาและค้นหาผ่านทางคอร์ดัมพ์
คู่ปรับ Shot

คำตอบ:


195

abort()ส่งสัญญาณการเรียกกระบวนการSIGABRTนี่คือการabort()ทำงานโดยทั่วไป

abort()มักจะถูกเรียกใช้โดยฟังก์ชั่นห้องสมุดซึ่งตรวจจับข้อผิดพลาดภายในหรือข้อ จำกัด บางอย่างที่เสียหายอย่างรุนแรง ตัวอย่างเช่นmalloc()จะเรียกabort()ว่าโครงสร้างภายในของมันเสียหายโดยฮีปล้น


27
สำหรับฉันในกรณีส่วนใหญ่ SIGABRT ถูกส่งโดยlibcพยายามโทรหาพอยน์เตอร์free()ที่ไม่ได้กำหนดค่าเริ่มต้น / เสียหาย
grandrew

ถ้าฉันมีบางที่ในรหัสฝังการเรียกฟังก์ชั่นเสมือนบริสุทธิ์จากภายในนวกรรมิกนั่นอาจเป็นสัญญาณ SIGABRT หรือไม่ ฉันกำลังถามเมื่อฉันเห็นข้อผิดพลาดที่ระบุว่าฉันมีสายเสมือนจริงและบรรทัดถัดไปให้ข้อความ SIGABRT แก่ฉันและแอปพลิเคชันขัดข้องหรือถูกปิดโดยระบบปฏิบัติการ ขอบคุณ
Hrvoje

2
บน MacOS เราได้รับ SIGABRT เพื่อเปิดตัวจัดการไฟล์ประมาณ 1,000 ไฟล์โดยไม่ต้องปิด แทนที่จะเป็นการเยาะเย้ยการทดสอบของเราทำให้ไฟล์มีชนิดของผู้อ่านทั่วไปมากกว่าซึ่งไม่มีClose()วิธีการดังนั้นจึงถูกลืม มีความครอบคลุมที่ดีแม้ว่า : rolleyes:
Zyl

52

SIGABRTโดยทั่วไปจะใช้โดย libc และไลบรารีอื่น ๆ เพื่อยกเลิกโปรแกรมในกรณีที่เกิดข้อผิดพลาดร้ายแรง ตัวอย่างเช่น glibc ส่งSIGABRTกรณีที่ตรวจพบว่ามีการคอร์รัปชั่นแบบ double-free หรือ heap อื่น ๆ ที่ตรวจพบ

นอกจากนี้assertการใช้งานส่วนใหญ่ใช้SIGABRTในกรณีของการยืนยันที่ล้มเหลว

นอกจากนี้ยังSIGABRTสามารถส่งจากกระบวนการอื่น ๆ เช่นสัญญาณอื่น ๆ แน่นอนว่ากระบวนการส่งข้อมูลจำเป็นต้องรันด้วยผู้ใช้หรือรูทเดียวกัน


49

คุณสามารถส่งสัญญาณใด ๆ ไปยังกระบวนการใดก็ได้โดยใช้kill(2)อินเตอร์เฟส:

kill -SIGABRT 30823

30823 เป็นdashกระบวนการที่ฉันเริ่มต้นดังนั้นฉันสามารถหากระบวนการที่ฉันต้องการฆ่าได้อย่างง่ายดาย

$ /bin/dash
$ Aborted

Abortedผลผลิตเป็นที่เห็นได้ชัดว่าdashรายงาน SIGABRT

มันสามารถส่งโดยตรงไปยังกระบวนการใด ๆ ที่ใช้kill(2)หรือกระบวนการที่สามารถส่งสัญญาณไปที่ตัวเองผ่านทางassert(3), หรือabort(3)raise(3)


17

มันมักจะเกิดขึ้นเมื่อมีปัญหากับการจัดสรรหน่วยความจำ

มันเกิดขึ้นกับฉันเมื่อโปรแกรมของฉันพยายามจัดสรรอาร์เรย์ด้วยขนาดลบ


14

มีอีกสาเหตุที่ง่ายในกรณีของ c ++

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

เช่นขอบเขตของเธรดสิ้นสุดลงแล้ว แต่คุณลืมที่จะโทรเช่นกัน

thread::join();

หรือ

thread::detach();

7

GNU libc จะพิมพ์ข้อมูล/dev/ttyเกี่ยวกับเงื่อนไขที่ร้ายแรงก่อนที่จะโทรออกabort()(ซึ่งจะทริกเกอร์SIGABRT) แต่ถ้าคุณใช้โปรแกรมของคุณเป็นบริการหรือไม่ได้อยู่ในหน้าต่างเทอร์มินัลจริงข้อความเหล่านี้อาจสูญหายเนื่องจากไม่มี tty เพื่อแสดงข้อความ

ดูโพสต์ของฉันในการเปลี่ยนเส้นทาง libc เพื่อเขียนไปยัง stderr แทนที่จะเป็น / dev / tty:

การรับข้อความแสดงข้อผิดพลาด libc เปลี่ยนเส้นทางจาก / dev / tty


4

กรณีเมื่อกระบวนการได้รับ SIGABRT จากตัวเอง: Hrvoje พูดถึงเกี่ยวกับการถูกเรียกจาก ctor สร้างเสมือนจริงที่ถูกทำแท้งยกเลิกฉันสร้างตัวอย่างสำหรับสิ่งนี้ ที่นี่เมื่อจะสร้าง d มันจะเรียกคลาสพื้นฐานของ ctor และส่งผ่านตัวชี้ภายในไปยังตัวมันเอง ctor เรียกวิธีเสมือนบริสุทธิ์ก่อนตารางเต็มไปด้วยตัวชี้ที่ถูกต้องเพราะ d ยังไม่ได้สร้าง

#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;
}

คอมไพล์: g ++ -o aa aa.cpp

ulimit -c ไม่ จำกัด

run: ./aa

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

ตอนนี้ให้ดูไฟล์หลักได้อย่างรวดเร็วและตรวจสอบว่ามีการเรียก SIGABRT:

gdb aa core

ดู regs:

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

ตรวจสอบรหัส:

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

ในกรณีของฉันมันเป็นเพราะการป้อนข้อมูลในอาร์เรย์ที่ดัชนีเท่ากับความยาวของอาร์เรย์

string x[5];

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

    cin>>x[i];

}

x [5] กำลังเข้าถึงซึ่งไม่มีอยู่


1

ในฐานะที่เป็น "@sarnold" ชี้ให้เห็นอย่างเหมาะสมกระบวนการใด ๆ สามารถส่งสัญญาณไปยังกระบวนการอื่น ๆ ดังนั้นกระบวนการหนึ่งสามารถส่ง SIGABORT ไปยังกระบวนการอื่น & ในกรณีนั้นกระบวนการรับไม่สามารถแยกแยะได้ว่ามาจากการปรับแต่งเอง หน่วยความจำ ฯลฯ หรือคนอื่นมี "unicastly" ส่งไป

ในระบบใดระบบหนึ่งที่ฉันทำงานมีตัวตรวจจับการหยุดชะงักหนึ่งตัวที่ตรวจพบว่ากระบวนการออกมาจากงานบางอย่างด้วยการเต้นของหัวใจหรือไม่ หากไม่เป็นเช่นนั้นกระบวนการจะประกาศว่าอยู่ในสถานะหยุดชะงักและส่ง SIGABORT ไปให้

ฉันแค่ต้องการแบ่งปันผู้ที่คาดหวังนี้โดยอ้างอิงจากคำถามที่ถาม


0

ฉันจะให้คำตอบจากมุมมองการเขียนโปรแกรมการแข่งขัน (cp)แต่มันใช้กับโดเมนอื่นเช่นกัน

หลายครั้งในขณะที่ทำ cp ข้อ จำกัด มีขนาดค่อนข้างใหญ่

ตัวอย่างเช่น : ผมมีคำถามที่มีตัวแปรเป็นเช่นนั้นN, M, Q1 ≤ N, M, Q < 10^5

ความผิดพลาดที่ผมทำคือผมประกาศให้เป็น 2D จำนวนเต็มอาร์เรย์ของขนาด10000 x 10000ในC++และต่อสู้กับSIGABRTข้อผิดพลาดที่ Codechef เกือบ 2 วัน

ตอนนี้ถ้าเราคำนวณ:

ขนาดทั่วไปของจำนวนเต็ม: 4 ไบต์

จำนวนเซลล์ในอาร์เรย์ของเรา: 10,000 x 10,000

ขนาดทั้งหมด (เป็นไบต์): 400000000 ไบต์ = 4 * 10 ^ 8 ≈ 400 MB

โซลูชันของคุณสำหรับคำถามดังกล่าวจะทำงานบนพีซีของคุณ (ไม่เสมอไป) เนื่องจากสามารถจ่ายได้ขนาดนี้

แต่ทรัพยากรในเว็บไซต์การเข้ารหัส (ผู้ตัดสินออนไลน์) จำกัด อยู่เพียงไม่กี่ KB

ดังนั้นSIGABRTข้อผิดพลาดและข้อผิดพลาดอื่น ๆ

สรุป:

ในคำถามเช่นนี้เราไม่ควรประกาศอาร์เรย์หรือเวกเตอร์หรือ DS อื่น ๆ ที่มีขนาดนี้ แต่หน้าที่ของเราคือการทำให้อัลกอริทึมของเรามีประสิทธิภาพมากขึ้น

PS : อาจมีสาเหตุอื่น ๆ สำหรับข้อผิดพลาดนี้; ด้านบนเป็นหนึ่งในนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.