Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: pekfos
Kurs C++

Napisany program wysypuje się

[pytanie/odpowiedź] Napisany program wysypuje się - jak szukać przyczyny krytycznego błędu aplikacji

Program się wysypuje?

Jeśli po uruchomieniu programu, lub wykonaniu w nim określonej akcji, program przestaje działać, to najlepszą rzeczą jaką możesz w tym momencie zrobić, to uruchomić program pod debuggerem i spróbować powtórzyć okoliczności, w których wystąpił błąd.
» Kurs C++ » Poziom XDebugowanie w Visual Studio 2017 lekcja
W tym momencie program zostanie zatrzymany i twoje środowisko pokaże Ci linię która bezpośrednio wywołała błąd. Są szanse, że trafisz do obcego kodu, lub kod nie będzie w ogóle dostępny. W tej sytuacji, przejdź w dół call stacka do kodu, który będzie Ci mówił nieco więcej. Być może u podstawy błędu będzie dereferencja pustego wskaźnika, albo przekroczenie zakresu tablicy. Crash może być wywołany przez, na przykład, dzielenie przez zero, ale najczęściej jest to efekt błędnego odwołania do pamięci.
Adres użyty w błędnym odwołaniu również może informować o naturze problemu. W celu łatwiejszego identyfikowania błędnego użycia pamięci, pamięć niezainicjalizowana, czy zwolniona bywa nadpisywana magicznymi liczbami. Poniżej wartości które można spotkać pod Windowsem:
AdresOpis
0xCCCCCCCCPamięć niezainicjalizowana na stosie
0xCDCDCDCDPamięć niezainicjalizowana na stercie (dynamicznie zaalokowana)
0xDDDDDDDDPamięć zwolniona free()
0xFEEEFEEEPamięć zwolniona HeapFree()
0xFDFDFDFDNo man's land, dodatkowe bajty przed i po zaalokowanej pamięci
Jeśli uruchamiasz swój program przez środowisko programistyczne, to po jego zakończeniu zwykle gdzieś jest wypisywany kod zakończenia programu. W przypadku crasha, kod ten będzie jakąś bardzo dużą liczbą (ujemną lub dodatnią). Kod może być pokazany jako np. -1073741819, ale powinien być też tam w postaci szesnastkowej, a więc C0000005, lub 0xC0000005. Jeśli liczba jest pokazana tylko w systemie dziesiętnym, to konwersji można dokonać kalkulatorem Windows w widoku "Programisty" (ustaw długość liczby na DWORD). Ten kod jest cenną informacją dostarczaną przez system operacyjny:
HexDecOpis
0xC0000005-1073741819Błąd segmentacji (błędne odwołanie do pamięci - pusty wskaźnik, lub błędny wskaźnik)
0xC00000FD-1073741571Stack overflow - nieskończona rekurencja, lub skończona, ale zbyt głęboka rekurencja. Zbyt wiele danych na stosie (np. za duża tablica)
Te kody są najczęściej spotykane. Jeśli masz coś innego, wpisz kod w Google, najlepiej w postaci szesnastkowej. Opisy można znaleźć też tu: https://msdn.microsoft.com​/en-us/library/cc704588.aspx.

Gorsze błędy

Wyżej zaznaczyłem, że debugger pokazuje bezpośrednią przyczynę błędu aplikacji, a więc instrukcję, która wywołała wyjątek, a nie błąd w kodzie. Odwołanie pod adres X wywołuje problem, ale tak na prawdę problem jest w tym, że ten adres jest błędny, wcześniejszy kod niedostatecznie zadbał o poprawność tego adresu, lub go zepsuł. Przez te rozróżnienie, faktyczny bug w aplikacji może być daleko od miejsca, w którym bug się ujawnia. Nawet: bardzo daleko. To prowadzi do odrębnej klasy problemów z sypaniem się programu, którym dawno temu nadałem nieoficjalną nazwę najgorszych problemów jakich można nabawić się w C/C++. Zwykle scenariusz wygląda tak, że gdzieś w programie jest błędne odwołanie do pamięci, ale nie dość błędne, żeby wywołać wyjątek - a więc trafiona pamięć należy do tego samego programu. Później przychodzi użyć tej uszkodzonej pamięci i dochodzi do błędu. Cechą charakterystyczną takich błędów jest to, że nie stoi za nimi żadna większa logika i nie można przez to odtworzyć błędu. Bywa, że błąd pojawia się raz na kilka-kilkadziesiąt uruchomień programu, nigdy pod debuggerem i tylko przy włączonych optymalizacjach. Jeśli masz problem spełniający te objawy, ale ujawniający się niezależnie od optymalizacji kompilatora, zwiększ poziom ostrzeżeń, szukaj użyć niezainicjalizowanych zmiennych, zwykle wskaźników lub indeksów. Jeśli problem ujawnia się tylko przy włączonych optymalizacjach, do możliwych przyczyn dochodzą różne niezdefiniowane zachowania.