Program ulega awarii tylko podczas kompilacji wydania - jak debugować?

98

Mam tutaj problem typu „Kot Schroedingera” - mój program (właściwie zestaw testowy dla mojego programu, ale program mimo wszystko) ulega awarii, ale tylko wtedy, gdy jest zbudowany w trybie wydania i tylko wtedy, gdy jest uruchamiany z wiersza poleceń . Poprzez debugowanie jaskiniowców (tj. Nieprzyjemne komunikaty printf () w każdym miejscu), określiłem metodę testową, w której kod ulega awarii, chociaż niestety rzeczywista awaria wydaje się mieć miejsce w jakimś destruktorze, ponieważ ostatnie wiadomości śledzenia, które widzę, znajdują się w inne destruktory, które działają czysto.

Kiedy próbuję uruchomić ten program w Visual Studio, nie ulega awarii. To samo dotyczy uruchamiania z WinDbg.exe. Awaria występuje tylko podczas uruchamiania z wiersza poleceń. Dzieje się to w systemie Windows Vista, przy okazji, i niestety nie mam teraz dostępu do komputera XP, aby przetestować.

Byłoby naprawdę miło, gdybym mógł zmusić system Windows do wydrukowania śladu stosu lub czegoś innego niż zwykłe zakończenie programu tak, jakby zakończył się czysto. Czy ktoś ma jakąś radę, jak mogę uzyskać tutaj bardziej znaczące informacje i miejmy nadzieję, że naprawię ten błąd?

Edycja: Problem był rzeczywiście spowodowany przez tablicę poza granicami, którą opisuję bardziej w tym poście . Dziękuję wszystkim za pomoc w znalezieniu tego problemu!

Nik Reiman
źródło
Czy możesz podać próbkę tej metody testowej?
akalenuk
Nie, przepraszam, kod jest zbyt skomplikowany, aby go łatwo wkleić, a jak wspomniałem, nie dzieje się to w samej metodzie testowej, ale raczej w destruktorze. Jednak w tej metodzie nie ma niezainicjowanych wskaźników ani niczego podobnego.
Nik Reiman
3
Większość odpowiedzi to niewiele więcej niż domysły. Istnieje kilka typowych technik analizowania kompilacji zawierających awarie bez dołączania debuggera: stackoverflow.com/a/18513077/214777?stw=2
Sebastian
Może to nie twoja wina: czy poziom optymalizacji -O3 jest niebezpieczny w g ++?
Brent Bradburn

Odpowiedzi:

130

W 100% przypadków, które widziałem lub słyszałem, gdzie program C lub C ++ działa dobrze w debugerze, ale kończy się niepowodzeniem, gdy jest uruchamiany na zewnątrz, przyczyną jest zapisywanie poza końcem lokalnej tablicy funkcji. (Debugger umieszcza więcej na stosie, więc jest mniej prawdopodobne, że nadpiszesz coś ważnego).

James Curran
źródło
32
Niech ktoś da temu mężczyźnie cygaro! W moim przypadku przekazywałem StringBuilder, który nie miał wystarczająco dużej pojemności do funkcji P / Invoke. Wydaje mi się, że to tak, jakby ktoś pisał po twojej twarzy magicznym markerem, gdy śpisz: pod debuggerem kończą pisanie na twoim czole, więc nie zauważysz, ale bez debuggera w końcu dźgają cię w oko ... coś w tym rodzaju. Dzięki za tę wskazówkę!
Nicholas Piasecki
1
W moim przypadku okazało się, że był to problem z wyrównaniem na procesorze ARM używającym Obj-C.
Almo
1
11 lat później i to nadal brzmi prawdą ... nie zapomnij zarezerwować swoich wektorów.
dav
1
ok, więc jak zmienić zachowanie trybu debugowania, aby faktycznie można było debugować.
Paul Childs,
1
„Teraz wiem, gdzie szukać”, ale w jaki sposób wszystko, co działa podczas debugowania, mówi ci, gdzie jest problem. Chociaż myślę, że w większości przypadków twoja odpowiedź jest poprawna, a wiedza na temat tego, czego szukać, jest dobrym początkiem, przeszukanie dużej bazy kodów, aby dokładnie określić, gdzie jest problem, może być zbyt kosztowne.
Paul Childs,
56

Kiedy napotkałem wcześniej takie problemy, zwykle było to spowodowane zmienną inicjalizacją. W trybie debugowania zmienne i wskaźniki są automatycznie inicjowane do zera, ale w trybie wydania nie. Dlatego jeśli masz taki kod

int* p;
....
if (p == 0) { // do stuff }

W trybie debugowania kod w if nie jest wykonywany, ale w trybie wydania p zawiera niezdefiniowaną wartość, która prawdopodobnie nie będzie równa 0, więc kod jest wykonywany często, powodując awarię.

Sprawdziłbym twój kod pod kątem niezainicjowanych zmiennych. Może to również dotyczyć zawartości tablic.

David Dibben
źródło
Typowe przypadki to zapominanie o umieszczeniu zmiennej składowej na (jednej z) listy inicjalizującej składową konstruktora. Ma ten sam efekt, ale trudniej go znaleźć, jeśli nie wiesz, że powinieneś również poszukać właściwej inicjalizacji członka.
steffenj
1
W trybie debugowania zmienne są zwykle inicjowane jako „stała zdefiniowana przez kompilator”, której można użyć w debugowaniu, aby wskazać stan zmiennej. Na przykład: popularne są wskaźniki NULL lub 0xDeadBeef.
Martin York
Środowiska uruchomieniowe debugowania zazwyczaj inicjują pamięć do pewnej wartości niezerowej, w szczególności po to, aby testy wskaźnika NULL powodowały, że kod działał tak, jakby wskaźnik był różny od NULL. W przeciwnym razie masz kod, który działa poprawnie w trybie debugowania, który powoduje awarię trybu wydania.
Michael Burr
1
Nie, zmienne nie są w ogóle inicjalizowane i nadal można je „używać” w UB, dopóki nie zostaną przypisane. Jednak podstawowa zawartość pamięci jest często wstępnie wypełniana kodem 0x0000000 lub 0xDEADBEEF lub innymi rozpoznawalnymi wzorcami.
Wyścigi lekkości na orbicie
27

Do tej pory żadna odpowiedź nie próbowała dać poważnego przeglądu dostępnych technik debugowania aplikacji w wersji:

  1. Kompilacje wydania i debugowania zachowują się różnie z wielu powodów. Oto doskonały przegląd. Każda z tych różnic może powodować błąd w kompilacji wydania, który nie istnieje w kompilacji debugowania.

  2. Obecność debugera może również zmienić zachowanie programu , zarówno w przypadku kompilacji do wydania, jak i do debugowania. Zobacz tę odpowiedź. Krótko mówiąc, przynajmniej Visual Studio Debugger automatycznie używa sterty debugowania po dołączeniu do programu. Stertę debugowania można wyłączyć za pomocą zmiennej środowiskowej _NO_DEBUG_HEAP. Możesz to określić we właściwościach komputera lub w ustawieniach projektu w programie Visual Studio. Może to spowodować odtworzenie awarii po podłączeniu debugera.

    Więcej na temat debugowania uszkodzenia sterty tutaj.

  3. Jeśli poprzednie rozwiązanie nie działa, musisz przechwycić nieobsługiwany wyjątek i dołączyć debuger sekcji zwłok, gdy wystąpi awaria. Możesz użyć do tego np. WinDbg, szczegółów na temat dostępnych debuggerów post-mortem i ich instalacji w MSDN

  4. Możesz ulepszyć swój kod obsługi wyjątków, a jeśli jest to aplikacja produkcyjna, powinieneś:

    za. Zainstaluj niestandardową procedurę obsługi zakończenia przy użyciustd::set_terminate

    Jeśli chcesz zdebugować ten problem lokalnie, możesz uruchomić nieskończoną pętlę wewnątrz modułu obsługi zakończenia i przesłać tekst do konsoli, aby powiadomić Cię o std::terminatewywołaniu. Następnie dołącz debuger i sprawdź stos wywołań. Lub drukujesz ślad stosu zgodnie z opisem w tej odpowiedzi.

    W aplikacji produkcyjnej możesz chcieć wysłać raport o błędzie do domu, najlepiej razem z małym zrzutem pamięci, który pozwala przeanalizować problem zgodnie z opisem tutaj.

    b. Skorzystaj ze strukturalnego mechanizmu obsługi wyjątków firmy Microsoft, który umożliwia wychwytywanie wyjątków sprzętowych i programowych. Zobacz MSDN . Możesz zabezpieczyć części swojego kodu za pomocą SEH i użyć tego samego podejścia, co w a), aby debugować problem. SEH zawiera więcej informacji na temat wyjątku, który wystąpił, którego można użyć podczas wysyłania raportu o błędzie z aplikacji produkcyjnej.

Sebastian
źródło
16

Na co zwrócić uwagę:

Array overruns - debugger Visual Studio wstawia wypełnienie, które może zatrzymać awarie.

Warunki wyścigu - czy masz zaangażowanych wiele wątków, jeśli tak, sytuacja wyścigu pojawia się tylko wtedy, gdy aplikacja jest wykonywana bezpośrednio.

Łączenie - czy kompilacja wydania pobiera poprawne biblioteki.

Rzeczy do wypróbowania:

Minidump - naprawdę łatwy w użyciu (po prostu sprawdź w msdn) daje pełny zrzut awaryjny dla każdego wątku. Po prostu ładujesz dane wyjściowe do programu Visual Studio i wygląda to tak, jakbyś debugował w momencie awarii.

morechilli
źródło
1
Cześć. Oddałem anonimowy głos w sprawie tej odpowiedzi. Chciałbym zrozumieć, dlaczego?
morechilli
12

Możesz ustawić WinDbg jako debugger postmortem. Spowoduje to uruchomienie debugera i dołączenie go do procesu po wystąpieniu awarii. Aby zainstalować WinDbg do debugowania pośmiertnego, użyj opcji / I (pamiętaj, że jest to pisane wielkimi literami ):

windbg /I

Więcej szczegółów tutaj .

Jeśli chodzi o przyczynę, jest to najprawdopodobniej zmienna zjednolicona, jak sugerują inne odpowiedzi.

Franci Penov
źródło
2
I nie zapominaj, że kompilator może generować pliki PDB nawet dla kompilacji wydania, chociaż nie jest to ustawienie domyślne.
Michael Burr
Jedyna prawdziwa odpowiedź na to pytanie.
Sebastian,
10

Po wielu godzinach debugowania w końcu znalazłem przyczynę problemu, który rzeczywiście był spowodowany przepełnieniem bufora, spowodowanym różnicą jednego bajtu:

char *end = static_cast<char*>(attr->data) + attr->dataSize;

To jest błąd słupka ogrodzenia (błąd oddzielenia o jeden) i został naprawiony przez:

char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;

Dziwne było to, że wykonałem kilka wywołań funkcji _CrtCheckMemory () wokół różnych części mojego kodu i zawsze zwracały one 1. Udało mi się znaleźć źródło problemu, umieszczając „return false”; wywołania w przypadku testowym, a następnie ostatecznie określają metodą prób i błędów, gdzie wystąpił błąd.

Dziękuję wszystkim za komentarze - wiele się dziś nauczyłem o windbg.exe! :)

Nik Reiman
źródło
8
Dzisiaj debugowałem podobny problem i _CrtCheckMemory () zawsze zwracało 1. Ale potem zdałem sobie sprawę, dlaczego: w trybie wydania _CrtCheckMemory jest # zdefiniowane jako ((int) 1).
Brian Morearty,
7

Nawet jeśli zbudowałeś swój exe jako wydanie, nadal możesz generować pliki PDB (baza danych programu), które pozwolą ci na śledzenie stosu i wykonywanie ograniczonej ilości inspekcji zmiennych. W ustawieniach kompilacji istnieje opcja tworzenia plików PDB. Włącz to i połącz ponownie. Następnie spróbuj najpierw uruchomić z IDE, aby sprawdzić, czy wystąpiła awaria. Jeśli tak, to świetnie - wszystko jest gotowe. Jeśli nie, to podczas uruchamiania z wiersza poleceń możesz zrobić jedną z dwóch rzeczy:

  1. Uruchom plik EXE i przed awarią wykonaj polecenie Dołącz do procesu (menu Narzędzia w programie Visual Studio).
  2. Po awarii wybierz opcję uruchomienia debugera.

Gdy pojawi się monit o wskazanie plików PDB, wyszukaj je. Jeśli pliki PDB zostały umieszczone w tym samym folderze wyjściowym, co pliki EXE lub DLL, prawdopodobnie zostaną automatycznie pobrane.

PDB zapewniają łącze do źródła z wystarczającą ilością informacji o symbolach, aby można było zobaczyć ślady stosu, zmienne itp. Możesz sprawdzić wartości normalnie, ale pamiętaj, że możesz uzyskać fałszywe odczyty, ponieważ przebieg optymalizacji może oznaczać tylko rzeczy pojawiają się w rejestrach lub dzieje się w innej kolejności niż się spodziewasz.

NB: Zakładam tutaj środowisko Windows / Visual Studio.

Greg Whitfield
źródło
3

Takie awarie są prawie zawsze powodowane, ponieważ IDE zwykle ustawia zawartość niezainicjowanej zmiennej na zera, null lub inną taką „rozsądną” wartość, podczas gdy podczas pracy natywnej otrzymasz dowolne losowe śmieci, które zbierze system.

Twój błąd jest zatem prawie na pewno, że używasz czegoś takiego, jak używasz wskaźnika, zanim zostanie on poprawnie zainicjowany i unikniesz tego w IDE, ponieważ nie wskazuje on na żadne niebezpieczne - lub wartość jest obsługiwana przez sprawdzanie błędów - ale w trybie wydania robi coś paskudnego.

Cruachan
źródło
3

Aby mieć zrzut awaryjny, który możesz przeanalizować:

  1. Wygeneruj pliki pdb dla swojego kodu.
  2. Rebase ma mieć pliki exe i dll załadowane na ten sam adres.
  3. Włącz debugger post mortem, taki jak Dr. Watson
  4. Sprawdź adres awarii za pomocą narzędzia takiego jak wyszukiwarka awarii .

Powinieneś także sprawdzić narzędzia w Narzędziach do debugowania dla systemu Windows . Możesz monitorować aplikację i zobaczyć wszystkie wyjątki pierwszej szansy, które były przed Twoim wyjątkiem drugiej szansy.

Mam nadzieję, że to pomoże...

Yuval Peled
źródło
3

Świetnym sposobem debugowania takiego błędu jest włączenie optymalizacji dla kompilacji debugowania.

Mgill404
źródło
2

Kiedyś miałem problem, gdy aplikacja zachowywała się podobnie do Twojej. Okazało się, że to paskudne przekroczenie bufora w sprintfie. Oczywiście zadziałało, gdy został uruchomiony z dołączonym debugerem. To, co zrobiłem, to zainstalowanie nieobsługiwanego filtru wyjątków ( SetUnhandledExceptionFilter ), w którym po prostu blokowałem nieskończenie (używając WaitForSingleObject na fałszywym dojściu z wartością limitu czasu INFINITE).

Więc mógłbyś coś w stylu:

long __stdcall MyFilter (EXCEPTION_POINTERS *)
{
    HANDLE hEvt = :: CreateEventW (0,1,0,0);
    if (hEvt)
    {
        if (WAIT_FAILED == :: WaitForSingleObject (hEvt, INFINITE))
        {
            // błąd dziennika
        }
    }

}
// gdzieś w twoim wmain / WinMain:
SetUnhandledExceptionFilter (MyFilter);

Następnie podłączyłem debugger po tym, jak błąd się ujawnił (program gui przestał odpowiadać).

Następnie możesz albo zrobić zrzut i pracować z nim później:

.dump / ma ścieżka_do_pliku_ zrzutu

Lub od razu go zdebuguj. Najprostszym sposobem jest śledzenie, gdzie kontekst procesora został zapisany przez maszynę obsługującą wyjątki środowiska wykonawczego:

sd esp Zakres 1003f

Polecenie przeszuka przestrzeń adresową stosu pod kątem rekordów KONTEKST pod warunkiem długości wyszukiwania. Zwykle używam czegoś takiego jak „l? 10000” . Uwaga, nie używaj nietypowo dużych liczb jako rekordu, którego szukasz, zwykle w pobliżu nieobsługiwanej ramki filtru wyjątków. 1003f to kombinacja flag (uważam, że odpowiada CONTEXT_FULL) używanej do przechwytywania stanu procesora. Twoje wyszukiwanie wyglądałoby podobnie do tego:

0: 000> sd esp l1000 1003f
0012c160 0001003f 00000000 00000000 00000000? ...............

Po uzyskaniu wyników użyj adresu w poleceniu cxr:

.cxr 0012c160

To przeniesie Cię do tego nowego KONTEKSTU dokładnie w momencie awarii (otrzymasz dokładny ślad stosu w momencie awarii aplikacji). Dodatkowo użyj:

.exr -1

aby dowiedzieć się, który dokładnie wyjątek wystąpił.

Mam nadzieję, że to pomoże.

deemok
źródło
2

Czasami dzieje się tak, ponieważ ważna operacja została zapakowana w makro „assert”. Jak być może wiesz, "assert" ocenia wyrażenia tylko w trybie debugowania.

Mohamad mehdi Kharatizadeh
źródło
1

W odniesieniu do problemów z uzyskiwaniem informacji diagnostycznych, czy próbowałeś użyć adplus.vbs jako alternatywy dla WinDbg.exe? Aby dołączyć do działającego procesu, użyj

adplus.vbs -crash -p <process_id>

Lub aby uruchomić aplikację w przypadku, gdy awaria nastąpi szybko:

adplus.vbs -crash -sc your_app.exe

Pełne informacje na temat adplus.vbs można znaleźć pod adresem : http://support.microsoft.com/kb/286350

DocMax
źródło
1

Ntdll.dll z dołączonym debugerem

Niewielka różnica między uruchomieniem programu z IDE lub WinDbg a uruchomieniem go z wiersza poleceń / pulpitu polega na tym, że podczas uruchamiania z dołączonym debugerem (tj. IDE lub WinDbg), ntdll.dll używa innej implementacji sterty, która przeprowadza niewielką weryfikację na alokację / zwalnianie pamięci.

Możesz przeczytać kilka istotnych informacji w nieoczekiwanym punkcie przerwania użytkownika w ntdll.dll . Jednym z narzędzi, które mogą pomóc w zidentyfikowaniu problemu, jest PageHeap.exe .

Analiza awarii

Nie napisałeś, co to za „awaria”, której doświadczasz. Gdy program ulegnie awarii i zaproponuje wysłanie informacji o błędzie do firmy Microsoft, powinieneś być w stanie kliknąć informacje techniczne i sprawdzić przynajmniej kod wyjątku, a przy pewnym wysiłku możesz nawet przeprowadzić analizę pośmiertną (patrz Heisenbug : Program WinApi ulega awarii na niektórych komputerach) w celu uzyskania instrukcji)

Suma
źródło
1

Vista SP1 ma naprawdę fajny generator zrzutów awaryjnych wbudowany w system. Niestety nie jest on domyślnie włączony!

Zobacz ten artykuł: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx

Zaletą tego podejścia jest to, że w systemie, którego dotyczy luka, nie trzeba instalować żadnego dodatkowego oprogramowania. Chwyć i rozerwij, kochanie!


źródło
1

Z mojego doświadczenia wynika, że ​​większość z nich dotyczy uszkodzenia pamięci.

Na przykład :

char a[8];
memset(&a[0], 0, 16);

: /*use array a doing some thing */

bardzo możliwe jest normalne działanie w trybie debugowania po uruchomieniu kodu.

Ale w wydaniu to by / mogło się zawiesić.

Dla mnie grzebanie tam, gdzie pamięć jest poza zasięgiem, jest zbyt uciążliwe.

Użyj niektórych narzędzi, takich jak Visual Leak Detector (Windows) lub Valgrind (Linux), które są mądrzejsze.

Gaiger Chen
źródło
1

Widziałem wiele prawidłowych odpowiedzi. Jednak nie ma nikogo, kto mi pomógł. W moim przypadku wystąpiło nieprawidłowe użycie instrukcji SSE z niewyrównaną pamięcią . Spójrz na swoją bibliotekę matematyczną (jeśli jej używasz) i spróbuj wyłączyć obsługę SIMD, ponownie skompiluj i odtworzyć awarię.

Przykład:

Projekt zawiera mathfu i używa klas z wektorem STL: std :: vector <mathfu :: vec2> . Takie użycie prawdopodobnie spowoduje zawieszenie się podczas konstruowania elementu mathfu :: vec2, ponieważ domyślny alokator STL nie gwarantuje wymaganego 16-bajtowego wyrównania. W tym przypadku, aby udowodnić pomysł, można zdefiniować #define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1przed każdym włączeniem mathfu , ponownie skompilować w konfiguracji wydania i sprawdzić ponownie.

Do debugowania i RelWithDebInfo konfiguracje pracował dobrze dla mojego projektu, ale nie do wydania jednego. Przyczyną tego zachowania jest prawdopodobnie to, że debugger przetwarza żądania alokacji / zwalniania alokacji i wykonuje pewne księgowania pamięci, aby sprawdzić i zweryfikować dostęp do pamięci.

Doświadczyłem takiej sytuacji w środowiskach Visual Studio 2015 i 2017.

Vlad Serhiienko
źródło
0

Coś podobnego spotkało mnie kiedyś z GCC. Okazało się, że była to zbyt agresywna optymalizacja, która została włączona tylko podczas tworzenia ostatecznej wersji, a nie podczas procesu rozwoju.

Cóż, prawdę mówiąc, to była moja wina, a nie gcc, ponieważ nie zauważyłem, że mój kod opiera się na fakcie, że ta konkretna optymalizacja nie została wykonana.

Znalezienie go zajęło mi dużo czasu i doszedłem do niego tylko dlatego, że zapytałem na grupie dyskusyjnej i ktoś zmusił mnie do przemyślenia. Więc pozwól mi odwzajemnić przysługę, na wypadek, gdyby ci się to przytrafiło.

Remo.D
źródło
0

Znalazłem to ten artykuł przydatny dla scenariusza. ISTR, opcje kompilatora były trochę nieaktualne. Rozejrzyj się po opcjach projektu programu Visual Studio, aby zobaczyć, jak generować pliki pdb dla kompilacji wydania itp.

fizzer
źródło
0

Jest podejrzane, że wydarzy się to poza debugerem, a nie wewnątrz; uruchomienie w debugerze zwykle nie zmienia zachowania aplikacji. Sprawdziłbym różnice środowiskowe między konsolą a IDE. Oczywiście skompiluj wydanie bez optymalizacji iz informacjami o debugowaniu i sprawdź, czy ma to wpływ na zachowanie. Na koniec zapoznaj się z narzędziami do debugowania post-mortem, które sugerowały tutaj inne osoby, zwykle możesz uzyskać od nich jakąś wskazówkę.

Nacięcie
źródło
0

Debugowanie kompilacji wersji może być uciążliwe ze względu na optymalizacje zmieniające kolejność, w której wiersze kodu wydają się być wykonywane. To naprawdę może być mylące!

Jedną z technik pozwalających przynajmniej zawęzić problem jest użycie MessageBox () do wyświetlenia szybkich instrukcji określających, do jakiej części programu należy twój kod ("Uruchamianie Foo ()", "Uruchamianie Foo2 ()"); zacznij umieszczać je na górze funkcji w obszarze twojego kodu, który podejrzewasz (co robiłeś w czasie, gdy się zawiesił?). Kiedy możesz określić, która funkcja, zmień pola komunikatów na bloki kodu lub nawet pojedyncze wiersze w ramach tej funkcji, dopóki nie zawęzisz jej do kilku wierszy. Następnie możesz rozpocząć drukowanie wartości zmiennych, aby zobaczyć, w jakim stanie są w momencie awarii.


źródło
Próbował już spryskać printfs, więc skrzynki z wiadomościami nie wygrały; nie wnoś niczego nowego na imprezę.
Greg Whitfield
0

Spróbuj użyć funkcji _CrtCheckMemory (), aby zobaczyć, w jakim stanie jest przydzielona pamięć. Jeśli wszystko pójdzie dobrze, _CrtCheckMemory zwraca TRUE , w przeciwnym razie FALSE .

Vhaerun
źródło
0

Możesz uruchomić oprogramowanie z włączonymi flagami globalnymi (zajrzyj do narzędzi do debugowania dla systemu Windows). Bardzo często pomoże to rozwiązać problem.

Marcin Gil
źródło
0

Spraw, aby Twój program generował mini zrzut, gdy wystąpi wyjątek, a następnie otwórz go w debugerze (na przykład w WinDbg). Najważniejsze funkcje, którym należy się przyjrzeć: MiniDumpWriteDump, SetUnhandledExceptionFilter

mikhailitsky
źródło
0

Oto przypadek, który ktoś może uznać za pouczający. Zawiesił się tylko w wydaniu w Qt Creator, a nie w debugowaniu. Używałem plików .ini (ponieważ wolę aplikacje, które można skopiować na inne dyski, w porównaniu z tymi, które tracą ustawienia, jeśli rejestr zostanie uszkodzony). Dotyczy to wszystkich aplikacji, które przechowują swoje ustawienia w drzewie katalogów aplikacji. Jeśli kompilacje debugowania i wydania znajdują się w różnych katalogach, możesz mieć również inne ustawienia między nimi. Miałem zaznaczone preferencje w jednym, który nie był zaznaczony w drugim. Okazało się, że to było źródło mojej katastrofy. Dobrze, że to znalazłem.

Nienawidzę tego mówić, ale zdiagnozowałem awarię tylko w MS Visual Studio Community Edition; po zainstalowaniu VS, pozwoleniu mojej aplikacji na awarię w Qt Creator i wybraniu otwarcia jej w debugerze programu Visual Studio . Podczas gdy moja aplikacja Qt nie zawierała informacji o symbolach, okazuje się, że biblioteki Qt miały kilka. Doprowadziło mnie to do przestępstwa; ponieważ mogłem zobaczyć, jaka metoda została wywołana. (Mimo to uważam, że Qt to wygodny, potężny i wieloplatformowy framework LGPL.)

CodeLurker
źródło
0

Ja też miałem ten problem. W moim przypadku tryb RELEASE miał msvscrtd.dll w definicji konsolidatora. Usunęliśmy go i problem został rozwiązany.

Alternatywnie dodanie / NODEFAULTLIB do argumentów wiersza poleceń konsolidatora również rozwiązało problem.

Pavan Dittakavi
źródło
-3

Miałem ten błąd i vs się zawiesił, nawet gdy próbowałem! Wyczyścić! mój projekt. Więc usunąłem pliki obj ręcznie z katalogu Release, a potem wszystko dobrze się zbudowało.

Chris89
źródło
-6

Zgadzam się z Rolfem. Ponieważ odtwarzalność jest tak ważna, nie powinieneś mieć trybu bez debugowania. Wszystkie twoje kompilacje powinny dać się debugować. Posiadanie dwóch celów do debugowania więcej niż podwaja obciążenie debugowania. Po prostu wyślij wersję „trybu debugowania”, chyba że jest bezużyteczna. W takim przypadku uczyń go użytecznym.

mądry
źródło
Może to zadziałać w przypadku 10% aplikacji, ale z pewnością nie we wszystkich. Czy chciałbyś grać w gry wydane jako kompilacje DEBUG? Oddaj swój zastrzeżony znak towarowy tajny kod bezpieczeństwa w trybie umożliwiającym demontaż, może nawet razem z plikami PDB? Nie sądzę.
steffenj
Steffenj: Chcę, aby twórcy gier znajdowali błędy. Najlepiej, zanim wyślą, ale jeśli to nastąpi, chcę, aby byli w stanie uzyskać wystarczającą ilość informacji, aby je odtworzyć i wyśledzić. jeśli jest to tajny kod, znak towarowy nie ma zastosowania. PDB? Bank danych białek? debugger Pythona?
mądry
IMHO, to zły pomysł. Pliki wykonywalne są większe, nie są zoptymalizowane i działają dużo wolniej. Takie przypadki są naprawdę rzadkie; nawet jeśli są szczególnie irytujące, kiedy się zdarzają. Nie powinieneś dostarczać konsekwentnie gorszego produktu, martwiąc się o niezwykle rzadkie debugowanie w najgorszym przypadku. (Mój nie był jednym z wielu głosów przeciw). Zrobiłem trochę programów dla NASA; i powiedzieliśmy, że jako absolutne minimum każdy wiersz kodu powinien zostać przetestowany raz. Pomocne mogą być również testy jednostkowe.
CodeLurker