Application Verifier w połączeniu z Debugging Tools for Windows to niesamowita konfiguracja. Możesz uzyskać oba jako część zestawu Windows Driver Kit lub lżejszego Windows SDK . (Dowiedziałem się o Application Verifier podczas badania wcześniejszego pytania o problem z uszkodzeniem sterty ). W przeszłości również korzystałem z BoundsChecker i Insure ++ (wspomnianych w innych odpowiedziach), chociaż byłem zaskoczony, ile funkcji jest w Application Verifier.
Warto wspomnieć o Electric Fence (aka „efence”), dmalloc , valgrind i tak dalej, ale większość z nich jest znacznie łatwiejsza do uruchomienia pod * nix niż Windows. Valgrind jest absurdalnie elastyczny: debugowałem oprogramowanie dużego serwera z wieloma problemami ze stertą, używając go.
Kiedy wszystko inne zawiedzie, możesz zapewnić własnego globalnego operatora przeciążenia new / delete i malloc / calloc / realloc - jak to zrobić, będzie się nieco różnić w zależności od kompilatora i platformy - i będzie to trochę inwestycja - ale na dłuższą metę może się opłacić. Lista pożądanych funkcji powinna wyglądać znajomo z dmalloc i electricfence oraz zaskakująco doskonałej książki Writing Solid Code :
- wartości wartowników : zapewniają trochę więcej miejsca przed i po każdym przydziale, przestrzegając maksymalnego wymogu dostosowania; wypełnij magicznymi liczbami (pomaga wychwycić przepełnienia i niedomiary bufora oraz sporadyczny „dziki” wskaźnik)
- przydziel wypełnienie : wypełnij nowe alokacje magiczną wartością różną od 0 - Visual C ++ zrobi to już za Ciebie w kompilacjach debugowania (pomaga złapać użycie niezainicjowanych zmiennych)
- bezpłatne wypełnienie : wypełnij zwolnioną pamięć magiczną wartością różną od 0, zaprojektowaną w celu wywołania segfault, jeśli jest wyłuskana w większości przypadków (pomaga złapać wiszące wskaźniki)
- opóźnione wolne : nie zwracaj zwolnionej pamięci na stos przez chwilę, utrzymuj ją jako wolną wypełnioną, ale niedostępną (pomaga złapać więcej zwisających wskaźników, łapie bliższe podwójne zwolnienia)
- śledzenie : możliwość zarejestrowania, gdzie dokonano alokacji, może być czasami przydatna
Zwróć uwagę, że w naszym lokalnym systemie homebrew (dla osadzonego celu) śledzenie jest oddzielone od większości innych rzeczy, ponieważ narzut czasu wykonywania jest znacznie wyższy.
Jeśli interesuje Cię więcej powodów, aby przeciążać te funkcje / operatory alokacji, spójrz na moją odpowiedź na pytanie „Czy jest jakiś powód, aby przeciążać operatora globalnego nowy i usunąć?” ; Pomijając bezwstydną autopromocję, wymienia inne techniki, które są pomocne w śledzeniu błędów uszkodzenia sterty, a także inne odpowiednie narzędzia.
Ponieważ wciąż znajduję tutaj własną odpowiedź, szukając wartości przydziału / wolnego / ogrodzenia, których używa MS, oto kolejna odpowiedź, która obejmuje wartości wypełnienia dbgheap firmy Microsoft .
Możesz wykryć wiele problemów z uszkodzeniem sterty, włączając stertę strony dla swojej aplikacji. Aby to zrobić, musisz użyć programu gflags.exe, który jest częścią narzędzi debugowania dla systemu Windows
Uruchom Gflags.exe iw opcjach pliku obrazu dla pliku wykonywalnego zaznacz opcję „Włącz stos stron”.
Teraz uruchom ponownie exe i dołącz do debugera. Po włączeniu stosu strony aplikacja włamie się do debugera za każdym razem, gdy nastąpi uszkodzenie sterty.
źródło
Aby naprawdę spowolnić działanie i przeprowadzić wiele sprawdzeń w czasie wykonywania, spróbuj dodać następujący element u góry swojego
main()
lub odpowiednika w programie Microsoft Visual Studio C ++źródło
Bardzo istotnym artykułem jest debugowanie uszkodzenia sterty za pomocą narzędzia Application Verifier i Debugdiag .
źródło
Wykonywanie niegrzecznych rzeczy z pamięcią, np. Zapisywanie po zakończeniu bufora lub zapisywanie do bufora po jego zwolnieniu z powrotem na stertę.
Użyj narzędzia, które dodaje automatyczne sprawdzanie granic do twojego pliku wykonywalnego: np. Valgrind w systemie Unix lub narzędzie takie jak BoundsChecker (Wikipedia sugeruje również Purify i Insure ++) w systemie Windows.
Pamiętaj, że spowalniają one twoją aplikację, więc mogą być bezużyteczne, jeśli twoja aplikacja jest aplikacją czasu rzeczywistego.
Inną możliwą pomocą / narzędziem debugowania może być HeapAgent firmy MicroQuill.
źródło
Jedna szybka wskazówka, którą otrzymałem od wykrywania dostępu do zwolnionej pamięci, jest taka:
źródło
Najlepszym narzędziem, które uznałem za przydatne i działało za każdym razem, jest recenzja kodu (z dobrymi recenzentami kodu).
Oprócz przeglądu kodu, najpierw spróbuję Page Heap . Konfiguracja strony Heap zajmuje kilka sekund i przy odrobinie szczęścia może wskazać problem.
Jeśli nie masz szczęścia ze stosem strony, pobierz narzędzia debugowania dla systemu Windows od firmy Microsoft i naucz się korzystać z WinDbg. Niestety nie mogłem udzielić ci bardziej szczegółowej pomocy, ale debugowanie wielowątkowego uszkodzenia sterty jest bardziej sztuką niż nauką. Google dla hasła „uszkodzenie stosu WinDbg” i powinieneś znaleźć wiele artykułów na ten temat.
źródło
Możesz również sprawdzić, czy tworzysz link do dynamicznej, czy statycznej biblioteki wykonawczej C. Jeśli pliki DLL są łączone ze statyczną biblioteką wykonawczą C, pliki DLL mają oddzielne stosy.
Dlatego gdybyś utworzył obiekt w jednej bibliotece DLL i spróbował zwolnić go w innej bibliotece DLL, otrzymasz ten sam komunikat, który widzisz powyżej. Do tego problemu odwołuje się inne pytanie dotyczące przepełnienia stosu, zwalnianie pamięci przydzielonej w innej bibliotece DLL .
źródło
Jakiego rodzaju funkcji alokacji używasz? Niedawno napotkałem podobny błąd, używając funkcji alokacji w stylu Heap *.
Okazało się, że omyłkowo tworzyłem stertę z
HEAP_NO_SERIALIZE
opcją. To zasadniczo sprawia, że funkcje Heap działają bez zabezpieczenia wątków. Jest to poprawa wydajności, jeśli jest używana prawidłowo, ale nie powinna być używana, jeśli używasz HeapAlloc w programie wielowątkowym [1]. Wspominam o tym tylko dlatego, że w Twoim poście wspomniano, że masz aplikację wielowątkową. Jeśli używasz HEAP_NO_SERIALIZE gdziekolwiek, usuń to, a to prawdopodobnie rozwiąże problem.[1] Istnieją pewne sytuacje, w których jest to dozwolone, ale wymaga serializacji wywołań Heap * i zazwyczaj nie ma to miejsca w przypadku programów wielowątkowych.
źródło
Jeśli te błędy pojawiają się losowo, istnieje duże prawdopodobieństwo, że napotkałeś wyścig danych. Proszę sprawdzić: czy modyfikujesz wskaźniki pamięci współdzielonej z różnych wątków? Intel Thread Checker może pomóc wykryć takie problemy w programie wielowątkowym.
źródło
Oprócz szukania narzędzi, rozważ poszukanie prawdopodobnego sprawcy. Czy jest jakiś komponent, którego używasz, być może nie napisany przez Ciebie, który mógł nie zostać zaprojektowany i przetestowany do działania w środowisku wielowątkowym? Lub po prostu taki, o którym nie wiesz , działał w takim środowisku.
Ostatnim razem, gdy mi się to przydarzyło, był to pakiet natywny, który przez lata był z powodzeniem używany z zadań wsadowych. Ale to był pierwszy raz w tej firmie, kiedy został użyty z usługi internetowej .NET (która jest wielowątkowa). To było to - skłamali, że kod jest bezpieczny dla wątków.
źródło
Możesz użyć makr VC CRT Heap-Check dla _CrtSetDbgFlag : _CRTDBG_CHECK_ALWAYS_DF lub _CRTDBG_CHECK_EVERY_16_DF .. _CRTDBG_CHECK_EVERY_1024_DF .
źródło
Chciałbym dodać swoje doświadczenie. W ciągu ostatnich kilku dni rozwiązałem wystąpienie tego błędu w mojej aplikacji. W moim przypadku błędy w kodzie to:
Control.Invoke
i usuń obiekt zarządzany, który opakowuje obiekt natywny, do którego należy wywołanie zwrotne.Control.Invoke
końca). Powinienem wyjaśnić, że używamboost::thread
, więc używam funkcji składowej jako funkcji wątku.Control.BeginInvoke
Zamiast tego użyj (mój GUI jest tworzony za pomocą Winforms), aby natywny wątek mógł zakończyć się przed zniszczeniem obiektu (celem wywołania zwrotnego jest precyzyjne powiadomienie, że wątek się skończył i obiekt może zostać zniszczony).źródło
Miałem podobny problem - i pojawiał się dość przypadkowo. Być może coś było uszkodzone w plikach kompilacji, ale ostatecznie naprawiłem to, najpierw czyszcząc projekt, a następnie przebudowując.
Więc oprócz innych udzielonych odpowiedzi:
Jakie rzeczy mogą powodować te błędy? Coś jest uszkodzone w pliku kompilacji.
Jak je debugować? Czyszczenie projektu i przebudowa. Jeśli problem został rozwiązany, prawdopodobnie był to problem.
źródło