Heap korupcja pod Win32; jak znaleźć?

głosy
54

Pracuję na wielowątkowych aplikacji C ++, który psuje sterty. Zwykłe narzędzia dla zlokalizowania uszkodzenia wydają się być zastosowania. Stary buduje (18 miesięcy) z kodu źródłowego wykazują takie samo zachowanie jak najnowszej wersji, więc to już od dłuższego czasu i po prostu nie został zauważony; na domiar złego, delty źródłowe nie mogą być wykorzystywane do identyfikacji, gdy błąd został wprowadzony - istnieje wiele zmian kodu w repozytorium.

Monit do awarii behaviuor jest generowanie przepustowości w systemie - przeniesienie gniazda danych, które są munged w reprezentację wewnętrznego. Mam zestaw danych testowych, które okresowo powodować aplikację do wyjątku (różnych miejscach, w tym różne przyczyny - sterty alloc niedostatecznej sposób: uszkodzenie stosu).

Zachowanie wydaje się podobne do mocy procesora i przepustowości pamięci; tym bardziej każdego maszyna, tym łatwiej jest rozbić. Wyłączenie rdzeń hiperwątkowość lub rdzeń dwurdzeniowy zmniejsza szybkość (ale nie eliminuje) skażenia. To sugeruje rozrządu związane problem.

Teraz tutaj jest sęk:
Kiedy jest prowadzony pod środowisku lekki debugowania (powiedzmy Visual Studio 98 / AKA MSVC6) korupcja sterta jest stosunkowo łatwe do odtworzenia - dziesięć lub piętnaście minut przechodzą przed czymś nie horrendalnie i wyjątki, niczym alloc;podczas jazdy pod wyszukanym środowiskiem debugowania (Rational oczyszczenie VS2008/MSVC9lub nawet Microsoft Application Weryfikator) system staje się pamięć prędkości związany i nie upaść (Memory-bound: CPU nie jest coraz wyżej 50%, lekki dysk nie jest włączona, program będzie jak szybko to możliwe, skrzynka spożywania 1.3G2G RAM) , Tak, mam do wyboru jest w stanie odtworzyć problemu (ale nie zidentyfikować przyczynę) lub jest w stanie idenify przyczyny lub problem I nie można odtworzyć.

Moje obecne najlepsze zgadnąć, gdzie się obok jest:

  1. Uzyskaj szalenie Grunty okno (aby zastąpić obecną pole dev: 2GB RAM w E6550 Core2 Duo); to pozwoli na powtórzenia błędu katastrofy powodując błędnego zachowania, gdy uruchomiony pod potężnym środowiskiem debugowania; lub
  2. Przepisz operatorów newi deleteużywać VirtualAlloci VirtualProtectoznaczyć pamięć tylko do odczytu tak szybko, jak to się robi z. Uruchomić pod MSVC6i mieć OS złapać złe-faceta, który pisze na uwolnionym pamięci. Tak, jest to oznaka desperacji: kim jest przepisuje piekło newi delete?! Zastanawiam się, czy to się dzieje, aby to tak wolno, jak pod Purify et al.

A no: Dostawa z Oczyszczono oprzyrządowanie wbudowane w nie jest rozwiązaniem.

Kolega właśnie mijał i zapytał „przepełnienie stosu? Czy jesteśmy coraz stosu przelewa teraz?!?”

I teraz pytanie: Jak mogę zlokalizować Koruptor sterty?


Aktualizacja: równoważenie new[]i delete[]wydaje się, że dostał długą drogę w kierunku rozwiązania problemu. Zamiast 15 min, aplikacja teraz przechodzi około dwóch godzin przed upaść. Jeszcze nie tam. Wszelkie dalsze sugestie? Korupcja sterty ustąpi.

Aktualizacja: build release pod Visual Studio 2008 wydaje się znacznie lepiej; Prąd podejrzenie opiera się na STLwdrażaniu, że statki z VS98.


  1. Odtworzyć problem. Dr Watsonbędzie produkować zrzutu, które mogą być pomocne w dalszej analizie.

Wezmę pod uwagę, ale obawiam się, że Dr Watson zostanie wyzwolony tylko po fakcie, gdy nie wychodzi kupa Stomped dalej.

Kolejna próba może być używany WinDebugjako narzędzie do debugowania, który jest dość silny jest w tym samym czasie również lekki.

Zrozumiałeś dzieje w tej chwili, jeszcze raz: nie wiele pomóc, dopóki coś się nie uda. Chcę złapać wandala na gorącym uczynku.

Może narzędzia te pozwalają przynajmniej ograniczyć problem do określonego składnika.

I nie posiadają wiele nadziei, ale desperackie czasy wymagają ...

A jesteś pewien, że wszystkie elementy projektu mają poprawne ustawienia runtime library ( C/C++ tabkategoria Generowanie kodu w VS ustawieniami 6.0 projektu)?

Nie, nie jestem, a ja spędzić kilka godzin jutro przeżywa przestrzeni roboczej (58 projektów w nim) i sprawdzanie oni wszyscy zestawiania i łączenia z odpowiednimi flagami.


Aktualizacja: To trwało 30 sekund. Zaznacz wszystkie projekty w Settingsoknie dialogowym, odznacz aż znajdziesz projektu (ów), które nie mają prawa ustawienia (wszyscy mieli odpowiednie ustawienia).

Utwórz 04/08/2008 o 08:30
źródło użytkownik
W innych językach...                            


15 odpowiedzi

głosy
26

Moim pierwszym wyborem będzie dedykowane narzędzie sterty takich jak pageheap.exe .

Przepisywanie nowych i usuwanie może być przydatne, ale nie złapać ALLOCS popełnionych przez kod niższego poziomu. Jeśli to, co chcesz, lepiej objazd na low-level alloc APIS przy zastosowaniu Microsoft objazdów.

Także testy sprawdzające, takie jak: sprawdzenie bibliotek run-time mecz (release vs. debug, wielowątkowy vs. jednowątkowy, dll vs. lib statycznych), szukać złych usuwaniem (np usuwać gdzie delete [] powinien być używany), upewnij się, że nie jesteś mieszanie i dopasowywanie swoich ALLOCS.

Spróbuj również selektywnie wyłączyć wątki i zobaczyć, kiedy / jeśli problem zniknie.

Czego stos wywołań etc wyglądać w momencie pierwszego wyjątku?

Odpowiedział 04/08/2008 o 08:51
źródło użytkownik

głosy
11

Mam takie same problemy w mojej pracy (możemy również użyć VC6czasami). I nie ma prostego rozwiązania. Mam tylko kilka wskazówek:

  • Spróbuj z automatycznym katastrofie zrzuca na maszynie produkcyjnej (patrz Wywrotka Process ). Moje doświadczenie mówi dr Watson to nie idealny do dumpingu.
  • Usuń wszystkie catch (...) z kodu. Często ukrywają one poważne wyjątki pamięci.
  • Sprawdzić Windows Advanced debugowanie - istnieje wiele cennych wskazówek dla problemów takich jak Twoja. Polecam to z całego serca.
  • Jeśli używasz STLspróbować STLPorti sprawdzone buduje. Nieprawidłowy iterator są piekłem.

Powodzenia. Problemy takie jak Twoja nas miesiąc rozwiązać. Bądź gotowy na to ...

Odpowiedział 06/08/2008 o 13:41
źródło użytkownik

głosy
8

Uruchom aplikację z oryginalnego ADplus -crash -pn appnename.exe Kiedy kwestia pamięci pojawia się dostaniesz ładny, duży zrzut.

Można analizować zrzutu dowiedzieć co pamięć lokalizacja została uszkodzona. Jeśli masz szczęście pamięć nadpisywania to unikatowy ciąg można dowiedzieć się, skąd pochodzi. Jeśli nie masz szczęście, trzeba będzie kopać w win32sterty i dowiedzieć co było orignal cechy pamięci. (heap -x może pomóc)

Po wiesz, co się zawiedli-up, można ograniczyć zużycie weryfikatora aplikacji ze specjalnymi ustawieniami sterty. czyli można określić, co DLLmożna monitorować, czy co alokacja rozmiar monitorować.

Mam nadzieję, że będzie to przyspieszenie monitorowanie wystarczy złapać sprawcę.

Z mojego doświadczenia, nigdy nie potrzebował pełnego trybu sterty weryfikatora, ale spędziłem sporo czasu analizując zrzut awaryjny (ów) i źródeł przeglądania.

PS: Można użyć DebugDiag przeanalizować wysypisk. Może on zwrócić uwagę na DLLposiadającą uszkodzony sterty, i daje inne szczegóły użytecznych.

Odpowiedział 16/09/2008 o 08:33
źródło użytkownik

głosy
7

Mieliśmy dość szczęścia poprzez pisanie własnych funkcji malloc i wolne. W produkcji, po prostu zadzwoń do standardowego malloc i wolna, ale w debugowania, mogą robić, co chcesz. Mamy też prostą klasę bazową, że nic nie robi, ale zastępują nowe i usunąć operatorów do korzystania z tych funkcji, a następnie każda klasa piszesz może po prostu dziedziczą z tej klasy. Jeśli masz mnóstwo kodu, może to być bardzo trudne do zastąpienia wywołań malloc i wolne do nowego malloc i free (nie zapomnij realloc!), Ale na dłuższą metę jest to bardzo pomocne.

W książce Steve Maguire Pisanie lita kod (wysoce zalecane), istnieją przykłady debugowania rzeczy, które można zrobić w tych funkcji, takich jak:

  • Śledzić alokacji w celu znalezienia nieszczelności
  • Przydzielić więcej pamięci niż jest to konieczne i umieścić znaczniki na początku i na końcu pamięci - w czasie wolnym rutyny, można zapewnić te markery są nadal
  • memset pamięć z markerem środków (do znalezienia niezainicjowanego wykorzystania pamięci) i są wolne (w tym celu użycie pamięci free'd)

Innym dobrym pomysłem jest, aby nigdy nie używać takich rzeczy strcpy, strcatlub sprintf- zawsze używać strncpy, strncati snprintf. Pisaliśmy nasze własne wersje tych, jak również, aby upewnić się, że nie odpisuje na końcu bufora, a te zostały złowione zbyt wiele problemów.

Odpowiedział 22/08/2008 o 18:11
źródło użytkownik

głosy
4

Trzeba zaatakować ten problem zarówno z wykonywania i analizy statycznej.

Do analizy statycznej rozważyć kompilacji z PREfast ( cl.exe /analyze). Wykrywa niedopasowane deletei delete[], przepełnienia bufora oraz szereg innych problemów. Bądź przygotowany, chociaż, aby przebrnąć przez wiele kilobajtów ostrzeżenia L6, szczególnie jeśli projekt nadal jest L4nie rozwiązany.

PREfast jest dostępny z Visual Studio Team Systemu i, najwyraźniej , jako część systemu Windows SDK.

Odpowiedział 12/10/2008 o 22:55
źródło użytkownik

głosy
3

Czy to w słabym pamięć? Jeśli tak, to może być to, że nowy wraca NULLzamiast rzucania std :: bad_alloc. Starsze VC++kompilatory nie prawidłowo zaimplementować to. Jest artykuł o awariach alokacji pamięci Legacy rozbijających STLaplikacje zbudowane z VC6.

Odpowiedział 02/09/2008 o 07:03
źródło użytkownik

głosy
3

Pozorna przypadkowość korupcji pamięci brzmi bardzo podobnie do kwestii synchronizacji wątek - błąd jest odtwarzany w zależności od prędkości maszyny. Jeśli obiekty (chuncks pamięci) są dzielone pomiędzy wątków i synchronizacji (sekcja krytyczna, mutex, semafor, inne) prymitywów nie są na per-klasy (na obiekt, na klasę) zasadach, to jest możliwe, aby dojść do sytuacji, gdzie grupa (fragment pamięci) są usuwane / uwolniony w trakcie użytkowania, a stosowane po usunięte / zwolniona.

W teście tym, można dodać prymitywów synchronizacji do każdej klasy i metody. Spowoduje to, że twój kod wolniej, ponieważ wiele obiektów będzie musiał czekać na siebie, ale jeśli ta eliminuje uszkodzenie sterty, problem sterty korupcji staną się optymalizacja kodu jeden.

Odpowiedział 25/08/2008 o 20:55
źródło użytkownik

głosy
1

Jeśli zdecydujesz się przerobić new / delete, zrobiłem to i mieć prosty kod źródłowy w:

http://gandolf.homelinux.org/~smhanov/blog/?id=10

Ten łapie wycieków pamięci, a także wstawia dane osłony przed i po bloku pamięci do przechwytywania uszkodzenie sterty. można po prostu zintegrować z nim poprzez umieszczenie #include „Debug.h” na górze każdego pliku CPP oraz określenie debugowania i DEBUG_MEM.

Odpowiedział 17/09/2008 o 14:40
źródło użytkownik

głosy
1

Więc z ograniczoną informacje masz, może to być kombinacja jednego lub więcej rzeczy:

  • Wykorzystanie złe kupa, czyli podwójne FreeS, czytane po wolne, pisać po wolne, ustawiając flagę HEAP_NO_SERIALIZE z ALLOCS i uwalnia od wielu wątków na tej samej stercie
  • Brak pamięci
  • Zły kod (czyli przepełnienia bufora, cieków buforowe, itp)
  • Kwestie „Timing”

Jeśli to w ogóle pierwsze dwa ale nie ostatni, trzeba było złapać go teraz albo pageheap.exe.

Które najprawdopodobniej oznacza to ze względu na to, jak jest kod dostępu do pamięci współdzielonej. Niestety, śledzenie, że dół będzie raczej bolesne. Zsynchronizowany dostęp do współdzielonej pamięci często objawia się dziwne problemy „timing”. Rzeczy, jak nie za pomocą semantyki nabywać / zwalniające do synchronizowania dostępu do pamięci współdzielonej z flagą, nie stosując odpowiednio zamki itp

Przynajmniej, że to pomoże, aby móc śledzić alokacji jakoś, jak sugerowano wcześniej. Przynajmniej wtedy można zobaczyć, co tak naprawdę wydarzyło się aż uszkodzenie sterty i próbę zdiagnozowania od tego.

Ponadto, jeśli można łatwo przekierować przydziały do ​​wielu stosach, może chcesz spróbować, aby zobaczyć, czy też rozwiązuje problem lub wyniki w bardziej powtarzalny zachowanie buggy.

Kiedy testowaliśmy z VS2008, uciekłeś z HeapVerifier z zaoszczędzenia pamięci ustawiona na Tak? To może zmniejszyć wpływ wydajności podzielnika sterty. (Plus, trzeba biegać z nim Debug-> Start z weryfikatora aplikacji, ale może już wiedzieć.)

Można również spróbować debugowania z WinDbg i różnych zastosowań polecenia! sterty.

MSN

Odpowiedział 22/08/2008 o 17:51
źródło użytkownik

głosy
0

Kilka sugestii. Można wymienić obfite ostrzeżenia na W4 - Proponuję poświęcenie czasu, aby naprawić swój kod do kompilowania równo na poziomie ostrzegawczym 4 - to będzie przejść długą drogę, aby zapobiec subtelny trudno znaleźć błędy.

Po drugie - dla przełącznika / analizować - to faktycznie generuje obfite ostrzeżenia. Aby użyć tego przełącznika w moim projekcie, co zrobiłem, było stworzenie nowego pliku nagłówka używany #pragma ostrzeżenie, aby wyłączyć wszystkie dodatkowe ostrzeżenia generowane przez / analizować. Następnie w dalszej części pliku, włączam tylko te ostrzeżenia mi zależy. Następnie użyć przełącznika / FI kompilatora, aby wymusić ten plik nagłówka, które należy uwzględnić pierwszy we wszystkich jednostkach kompilacji. Powinno to pozwolić na użycie / analizować przełącznika podczas kontrolowania wyjście

Odpowiedział 03/10/2009 o 17:48
źródło użytkownik

głosy
0

Czy uważasz, że jest to sytuacja wyścigu? Jest wiele wątków dzieląc jedną kupę? Można dać każdego wątku prywatną sterty z HeapCreate, wówczas mogą one szybko biegać z HEAP_NO_SERIALIZE. W przeciwnym razie, sterty należy wątku bezpieczne, jeśli używasz wielowątkowe wersje bibliotek systemowych.

Odpowiedział 30/07/2009 o 14:48
źródło użytkownik

głosy
0

Mały czas musiałem rozwiązać podobny problem. Jeśli problem nadal istnieje Proponuję to zrobić: Monitorowanie wszystkich połączeń do nowych / delete i malloc / calloc / realloc / free. Robię jeden DLL wywozu funkcję do rejestru wszystkich połączeń. Ta funkcja otrzymać parametr identyfikacji swój kod źródłowy, wskaźnik przydzielonego obszaru i rodzaju oszczędności te informacje w tabeli rozmowy. Wszystko przydzielane / uwolniona para jest wyeliminowane. Na koniec trzeba albo po dokonaniu połączenia do innej funkcji do tworzenia raportu dla danych lewo. Dzięki temu można zidentyfikować błędnych połączeń (nowa / Free lub malloc / usuń) lub brakujące. Jeśli masz jakieś sprawy buforu nadpisane w kodzie zapisane informacje mogą być błędne, ale każdy test może wykryć / odkryć / include rozwiązanie awarii identyfikację. Wiele biegnie pomóc zidentyfikować błędy. Powodzenia.

Odpowiedział 19/12/2008 o 12:52
źródło użytkownik

głosy
0

sugestia Graeme jest z niestandardowego malloc / wolny jest dobrym pomysłem. Sprawdzić, czy można scharakteryzować jakiś wzór o korupcji daje uchwyt dźwigni.

Na przykład, jeśli jest ona zawsze w bloku o tej samej wielkości (powiedzmy 64 bajtów), a następnie zmienić parę malloc / free zawsze przeznaczyć 64 bajtowe kawałki własnej strony. Kiedy uwolnić klocek 64 bajt następnie ustawić bity ochrony pamięci na tej stronie, aby zapobiec czyta i Wites (używając VirtualQuery). Potem ktoś próbuje uzyskać dostęp do tej pamięci wygeneruje wyjątek, a nie psuje sterty.

To nie zakładamy, że liczba zaległych kawałki 64 bajtowych jest jedynie umiarkowana lub masz dużo pamięci do spalania w polu!

Odpowiedział 02/09/2008 o 05:23
źródło użytkownik

głosy
0

Moja pierwsza akcja będzie w następujący sposób:

  1. Zbudować binaria w wersji „Release”, ale tworzenie informacji debugowania plik (znajdziesz tę możliwość w ustawieniach projektu).
  2. Użyj Dr Watson jako debugger defualt (drwtsn32 -I) na komputerze, na którym chcesz odtworzyć problem.
  3. Repdroduce problem. Dr Watson będzie produkować zrzutu, które mogą być pomocne w dalszej analizie.

Kolejna próba może być za pomocą WinDebug jako narzędzie do debugowania, który jest dość silny jest w tym samym czasie również lekki.

Może narzędzia te pozwalają przynajmniej ograniczyć problem do określonego składnika.

A jesteś pewien, że wszystkie elementy projektu mają poprawne ustawienia runtime library (zakładka C / C ++, kategoria Generowanie kodu w VS 6.0 Ustawienia projektu)?

Odpowiedział 04/08/2008 o 09:26
źródło użytkownik

głosy
0

Próbowano stary buduje, ale to nie powód, nie można poddawać się dalej w historii repozytorium i widząc dokładnie wtedy, gdy błąd został wprowadzony?

W przeciwnym razie, chciałbym zaproponować dodanie prostego rejestrowania jakiegoś pomóc wyśledzić problem, choć jestem w rozterce, co konkretnie może chcesz się zalogować.

Jeśli można dowiedzieć się, co dokładnie może być przyczyną tego problemu, poprzez google i dokumentacji z wyjątków są uzyskiwanie, może to da dalszy wgląd na co zwracać uwagę w kodzie.

Odpowiedział 04/08/2008 o 08:48
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more