Jakie są scenariusze, w których proces otrzymuje SIGABRT w C ++? Czy ten sygnał zawsze pochodzi z procesu, czy może on być przesyłany z jednego procesu do drugiego?
Czy istnieje sposób na określenie, który proces wysyła ten sygnał?
Jakie są scenariusze, w których proces otrzymuje SIGABRT w C ++? Czy ten sygnał zawsze pochodzi z procesu, czy może on być przesyłany z jednego procesu do drugiego?
Czy istnieje sposób na określenie, który proces wysyła ten sygnał?
Odpowiedzi:
abort()
wysyła SIGABRT
sygnał wywołania , tak w abort()
zasadzie działa.
abort()
jest zwykle wywoływany przez funkcje biblioteczne, które wykrywają błąd wewnętrzny lub niektóre poważnie zerwane ograniczenie. Na przykład malloc()
zadzwoni, abort()
jeśli jego wewnętrzne struktury zostaną uszkodzone przez przepełnienie sterty.
libc
próbę wywołania free()
niezainicjalizowanego / uszkodzonego wskaźnika
Close()
metody, więc został zapomniany. Miałem świetny zasięg. : rolleyes:
SIGABRT
jest powszechnie używany przez libc i inne biblioteki do przerwania programu w przypadku krytycznych błędów. Na przykład glibc wysyła komunikat SIGABRT
w przypadku wykrycia podwójnego zwolnienia lub innych uszkodzeń sterty.
Ponadto większość assert
implementacji wykorzystuje SIGABRT
w przypadku nieudanego potwierdzenia.
Ponadto SIGABRT
może być wysyłany z dowolnego innego procesu, jak każdy inny sygnał. Oczywiście proces wysyłania musi przebiegać jako ten sam użytkownik lub root.
Możesz wysłać dowolny sygnał do dowolnego procesu za pomocą kill(2)
interfejsu:
kill -SIGABRT 30823
30823 to dash
proces, który rozpocząłem, więc mogłem łatwo znaleźć proces, który chciałem zabić.
$ /bin/dash
$ Aborted
Wynik Aborted
jest najwyraźniej jak dash
zgłasza SIGABRT.
To może być wysłany bezpośrednio do dowolnego procesu korzystania kill(2)
lub proces może wysłać sygnał do samego siebie poprzez assert(3)
, abort(3)
lub raise(3)
.
Jest jeszcze jedna prosta przyczyna w przypadku c ++.
std::thread::~thread{
if((joinable ())
std::terminate ();
}
tzn. zakres wątku zakończył się, ale zapomniałeś zadzwonić
thread::join();
lub
thread::detach();
GNU libc wydrukuje informacje /dev/tty
dotyczące niektórych krytycznych warunków przed wywołaniem abort()
(które następnie SIGABRT
się uruchomi), ale jeśli uruchamiasz swój program jako usługę lub w inny sposób nie w prawdziwym oknie terminala, wiadomość ta może się zgubić, ponieważ nie ma tty, aby wyświetlić wiadomości.
Zobacz mój post na temat przekierowywania libc do pisania do stderr zamiast / dev / tty:
Łapanie komunikatów o błędach libc, przekierowywanie z / dev / tty
W przypadku, gdy proces pobiera SIGABRT od siebie: Hrvoje wspomniał o zakopanej czystej wirtualnej istocie wywoływanej z ctor generującej przerwanie, odtworzyłem przykład tego. Tutaj, kiedy ma zostać zbudowane d, najpierw wywołuje swoją podstawową klasę ctor i przekazuje do siebie wskaźnik wewnętrzny. ctor wywołuje czystą wirtualną metodę, zanim tabela została wypełniona prawidłowym wskaźnikiem, ponieważ d nie jest jeszcze skonstruowany.
#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;
}
skompiluj: g ++ -o aa aa.cpp
ulimit -c nieograniczony
uruchom: ./aa
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
teraz pozwala szybko zobaczyć podstawowy plik i sprawdzić, czy SIGABRT rzeczywiście został nazwany:
gdb aa core
zobacz regs:
i r
rdx 0x6 6
rsi 0x69a 1690
rdi 0x69a 1690
rip 0x7feae3170c37
Sprawdź kod:
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
:)
Jak trafnie zauważył „@sarnold”, każdy proces może wysłać sygnał do dowolnego innego procesu, dlatego jeden proces może wysłać SIGABORT do innego procesu iw takim przypadku proces odbiorczy nie jest w stanie odróżnić, czy nadchodzi z powodu własnej modyfikacji pamięć itp., lub ktoś inny ma „monstrualnie”, wyślij do niej.
W jednym z systemów, w których pracowałem, jest jeden detektor impasu, który faktycznie wykrywa, czy proces wychodzi z jakiegoś zadania, dając bicie serca, czy nie. Jeśli nie, oznacza to, że proces znajduje się w stanie zakleszczenia i wysyła do niego SIGABORT.
Chciałem tylko podzielić się tym prospektywnym w odniesieniu do zadanego pytania.
Dam odpowiedź z perspektywy programowania konkurencyjnego (cp) , ale dotyczy to również innych domen.
Wiele razy podczas wykonywania cp ograniczenia są dość duże.
Na przykład : miałem pytanie z N, M, Q
takimi zmiennymi , że 1 ≤ N, M, Q < 10^5
.
Pomyłka robiłem ja ogłoszony 2D całkowitą tablicy wielkości 10000 x 10000
w C++
i zmagał się z SIGABRT
błędem w Codechef przez prawie 2 dni.
Teraz, jeśli obliczymy:
Typowy rozmiar liczby całkowitej: 4 bajty
Liczba komórek w naszej tablicy: 10000 x 10000
Całkowity rozmiar (w bajtach): 400000000 bajtów = 4 * 10 ^ 8 ≈ 400 MB
Twoje rozwiązania takich pytań będą działać na twoim komputerze (nie zawsze), ponieważ można sobie na to pozwolić.
Ale zasoby w witrynach kodujących (sędziowie online) są ograniczone do kilku KB.
Stąd SIGABRT
błąd i inne tego rodzaju błędy.
Wniosek:
W takich pytaniach nie powinniśmy deklarować tablicy ani wektora ani żadnego innego DS tej wielkości, ale naszym zadaniem jest uczynienie naszego algorytmu tak wydajnym, aby działał bez nich (DS) lub z mniejszą ilością pamięci.
PS : Mogą istnieć inne przyczyny tego błędu; powyżej był jednym z nich.