W jaki sposób można określić, gdzie w kodzie znajduje się błąd, który powoduje błąd segmentacji ?
Czy mój kompilator ( gcc
) może pokazać lokalizację błędu w programie?
c++
c
debugging
segmentation-fault
Trilarion
źródło
źródło
Odpowiedzi:
GCC nie może tego zrobić, ale GDB ( debugger ) z pewnością może. Skompiluj swój program za pomocą
-g
przełącznika, na przykład:Następnie użyj gdb:
Oto fajny samouczek ułatwiający rozpoczęcie pracy z GDB.
Miejsce, w którym dochodzi do awarii, jest zazwyczaj tylko wskazówką, gdzie w kodzie znajduje się „błąd, który ją powoduje”. Podana lokalizacja niekoniecznie jest miejscem, w którym występuje problem.
źródło
bt
jako skrótu dlabacktrace
.Możesz
valgrind
także spróbować: jeśli zainstalujeszvalgrind
i uruchomisznastępnie uruchomi twój program i wyświetli ślady stosu dla wszelkich błędów segfault, a także wszelkich nieprawidłowych odczytów lub zapisów pamięci i wycieków pamięci. To naprawdę bardzo przydatne.
źródło
--leak-check=full
nie pomoże w debugowaniu segfaultów. Przydaje się tylko do debugowania wycieków pamięci.Możesz również użyć zrzutu pamięci, a następnie zbadać go za pomocą gdb. Aby uzyskać przydatne informacje, musisz również skompilować się z
-g
flagą.Za każdym razem, gdy otrzymasz wiadomość:
plik core jest zapisywany w twoim bieżącym katalogu. Możesz to zbadać za pomocą polecenia
Plik zawiera stan pamięci w momencie awarii programu. Zrzut pamięci może być przydatny podczas wdrażania oprogramowania.
Upewnij się, że Twój system nie ustawia rozmiaru pliku zrzutu pamięci na zero. Możesz ustawić go na nieograniczony za pomocą:
ulimit -c unlimited
Ostrożnie! te podstawowe zrzuty mogą stać się ogromne.
źródło
Dostępnych jest wiele narzędzi, które pomagają debugować błędy segmentacji i chciałbym dodać do listy moje ulubione narzędzie: Odkażacze adresów (często w skrócie ASAN) .
Kompilatory Modern¹ mają poręczną
-fsanitize=address
flagę, która dodaje trochę czasu kompilacji i narzutu czasu wykonywania, co zapewnia więcej sprawdzania błędów.Zgodnie z dokumentacją, kontrole te domyślnie obejmują wychwytywanie błędów segmentacji. Zaletą jest to, że otrzymujesz ślad stosu podobny do danych wyjściowych gdb, ale bez uruchamiania programu w debugerze. Przykład:
Wynik jest nieco bardziej skomplikowany niż to, co wygenerowałby gdb, ale są też plusy:
Nie ma potrzeby odtwarzania problemu, aby otrzymać ślad stosu. Wystarczy włączyć flagę podczas programowania.
ASAN wychwytują znacznie więcej niż tylko błędy segmentacji. Wiele wejść poza granice zostanie przechwyconych, nawet jeśli ten obszar pamięci był dostępny dla procesu.
¹ To jest Clang 3.1+ i GCC 4.8+ .
źródło
Odpowiedź Lucasa na temat zrzutów rdzeni jest dobra. W moim .cshrc mam:
aby wyświetlić ślad, wpisując „rdzeń”. I datownik, żeby mieć pewność, że patrzę na właściwy plik :(.
Dodano : Jeśli wystąpi błąd powodujący uszkodzenie stosu , ślad zastosowany do zrzutu pamięci jest często śmieciami. W takim przypadku uruchomienie programu w gdb może dać lepsze wyniki, zgodnie z przyjętą odpowiedzią (przy założeniu, że błąd można łatwo odtworzyć). A także uważaj na wiele procesów jednocześnie zrzucających rdzeń; niektóre systemy operacyjne dodają PID do nazwy pliku podstawowego.
źródło
ulimit -c unlimited
w pierwszej kolejności włączyć zrzutów pamięci .Wszystkie powyższe odpowiedzi są poprawne i zalecane; ta odpowiedź jest pomyślana tylko jako ostateczność, jeśli żadne z wyżej wymienionych podejść nie może być użyte.
Jeśli wszystko inne zawiedzie, zawsze możesz przekompilować swój program za pomocą różnych tymczasowych instrukcji debug-print (np.
fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);
) Rozsianych po tym, co uważasz za odpowiednie części twojego kodu. Następnie uruchom program i obserwuj, jaki był ostatni wydruk debugowania wydrukowany tuż przed awarią - wiesz, że twój program zaszedł tak daleko, więc awaria musiała nastąpić po tym momencie. Dodaj lub usuń wydruki debugowania, skompiluj ponownie i uruchom test ponownie, aż zawęzisz go do pojedynczej linii kodu. W tym momencie możesz naprawić błąd i usunąć wszystkie tymczasowe wydruki debugowania.Jest to dość żmudne, ale ma tę zaletę, że działa prawie wszędzie - jedyne sytuacje, w których może się to nie udać, to brak dostępu do stdout lub stderr z jakiegoś powodu lub jeśli błąd, który próbujesz naprawić, to wyścig -warunek, którego zachowanie zmienia się, gdy zmienia się czas działania programu (ponieważ debug-print spowolni program i zmieni jego czas)
źródło