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ł?
Istnieje kilka sposobów. Najłatwiejszym sposobem, jeśli napisałeś program, jest zarejestrowanie procedury obsługi sygnału dla SIGABRT, która drukuje te informacje i opróżnia strumienie przed powrotem. Drugim najprostszym sposobem jest uruchomienie programu w ramach strace. Trzecim najłatwiejszym sposobem jest upewnienie się, że program generuje plik podstawowy, gdy ulega awarii, i sprawdzenie go za pomocą zrzutu pamięci.
Parthian Shot
Odpowiedzi:
195
abort()wysyła SIGABRTsygnał 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.
dla mnie w większości przypadków SIGABRT został wysłany przez libcpróbę wywołania free()niezainicjalizowanego / uszkodzonego wskaźnika
grand17
Jeśli mam gdzieś w kodzie zakopane czysto wirtualne wywołanie funkcji z poziomu konstruktora, czy to może skończyć się sygnałem SIGABRT? Pytam, gdy widzę błąd informujący, że mam czystą wirtualną rozmowę, a następny wiersz wyświetla mi komunikat SIGABRT, a aplikacja ulega awarii lub zostaje zamknięta przez system operacyjny. Dzięki.
Hrvoje,
2
Na MacOS mamy SIGABRT do otwierania około 1000 uchwytów plików bez ich zamykania. Zamiast kpienia nasze testy wyodrębniły plik bardziej ogólnym typem czytnika, który nie ma Close()metody, więc został zapomniany. Miałem świetny zasięg. : rolleyes:
Zyl
51
SIGABRTjest powszechnie używany przez libc i inne biblioteki do przerwania programu w przypadku krytycznych błędów. Na przykład glibc wysyła komunikat SIGABRTw przypadku wykrycia podwójnego zwolnienia lub innych uszkodzeń sterty.
Ponadto większość assertimplementacji wykorzystuje SIGABRTw przypadku nieudanego potwierdzenia.
Ponadto SIGABRTmoż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 dashproces, który rozpocząłem, więc mogłem łatwo znaleźć proces, który chciałem zabić.
$ /bin/dash
$ Aborted
Wynik Abortedjest najwyraźniej jak dashzgł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).
GNU libc wydrukuje informacje /dev/ttydotyczące niektórych krytycznych warunków przed wywołaniem abort()(które następnie SIGABRTsię 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:
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>usingnamespace std;class A {public:
A(A *pa){pa->f();}virtualvoid f()=0;};class D :public A {public:
D():A(this){}virtualvoid f(){cout<<"D::f\n";}};int main(){
D d;
A *pa =&d;
pa->f();return0;}
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 0x66
rsi 0x69a1690
rdi 0x69a1690
rip 0x7feae3170c37
Sprawdź kod:
disas 0x7feae3170c37
mov $0xea,%eax =234<-this is the kill syscall, sends signal to process
syscall <-----
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.
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 SIGABRTbłą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.
Odpowiedzi:
abort()
wysyłaSIGABRT
sygnał wywołania , tak wabort()
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ładmalloc()
zadzwoni,abort()
jeśli jego wewnętrzne struktury zostaną uszkodzone przez przepełnienie sterty.źródło
libc
próbę wywołaniafree()
niezainicjalizowanego / uszkodzonego wskaźnikaClose()
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 komunikatSIGABRT
w przypadku wykrycia podwójnego zwolnienia lub innych uszkodzeń sterty.Ponadto większość
assert
implementacji wykorzystujeSIGABRT
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.źródło
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ć.Wynik
Aborted
jest najwyraźniej jakdash
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 poprzezassert(3)
,abort(3)
lubraise(3)
.źródło
Zwykle dzieje się tak, gdy występuje problem z alokacją pamięci.
Zdarzyło mi się, gdy mój program próbował przydzielić tablicę o rozmiarze ujemnym.
źródło
Jest jeszcze jedna prosta przyczyna w przypadku c ++.
tzn. zakres wątku zakończył się, ale zapomniałeś zadzwonić
lub
źródło
GNU libc wydrukuje informacje
/dev/tty
dotyczące niektórych krytycznych warunków przed wywołaniemabort()
(które następnieSIGABRT
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
źródło
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.
skompiluj: g ++ -o aa aa.cpp
ulimit -c nieograniczony
uruchom: ./aa
teraz pozwala szybko zobaczyć podstawowy plik i sprawdzić, czy SIGABRT rzeczywiście został nazwany:
zobacz regs:
Sprawdź kod:
disas 0x7feae3170c37
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
:)
źródło
W moim przypadku było to spowodowane wejściem do tablicy o indeksie równym długości tablicy.
x [5] jest dostępny, który nie jest obecny.
źródło
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.
źródło
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 , że1 ≤ N, M, Q < 10^5
.Pomyłka robiłem ja ogłoszony 2D całkowitą tablicy wielkości
10000 x 10000
wC++
i zmagał się zSIGABRT
błędem w Codechef przez prawie 2 dni.Teraz, jeśli obliczymy:
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.
źródło