Haldy pod Win32; jak najít?

hlasů
54

Pracuji na vícevláknových ++ aplikací C, která je poškozením haldy. Obvyklé nástroje, jak najít tuto korupci se zdá být nepoužitelný. Old staví (18 měsíců) ze zdrojového kódu vykazují stejné chování jako nejnovější verze, takže to bylo asi na dlouhou dobu a stejně byl nevšiml; Na druhou stranu, zdroje delty nelze použít k identifikaci, kdy byla zavedena chyba - existuje spousta změn kódu v úložišti.

Výzva k padání behaviuor je vytvářet výkon v tomto systému - přenos zásuvka dat, která je munged do vnitřní reprezentace. Mám soubor údajů o zkoušce, který bude pravidelně způsobit aplikaci na výjimky (různá místa, různé příčiny - včetně haldy alloc selhání, tak: haldy).

Chování zdá vztahující se k výkonu CPU a šířku pásma paměti; čím více každý stroj má, tím snazší je k havárii. Deaktivace jádro hyper-threading nebo dvoujádrový jádro snižuje rychlost (ale neodstraňuje) korupci. To naznačuje problém časování související.

Tady je ten háček:
Pokud je to běh na základě lehké ladění prostředí (řekněme Visual Studio 98 / AKA MSVC6) Poškození haldy je poměrně snadné reprodukovat - deset nebo patnáct minut projít, než se něco selže strašně i výjimky, jako alloc;když běží pod propracovaným ladění prostředí (Rational Purify, VS2008/MSVC9nebo dokonce Microsoft Application Verifier) se systém stává paměť rychlostí vázán a není krach (paměť vázané: CPU není stále výše 50%, disk nesvítí, program se děje tak rychle, je v jejích silách, box konzumovat 1.3Gz 2G RAM) , Takže mám na výběr mezi schopen reprodukovat problém (ale ne určit příčinu), nebo budou moci v identifikaci příčiny nebo problém nemohu reprodukovat.

Můj současný nejlepší dohady o tom, kde se dál, je:

  1. Získat šíleně grunty krabici (která by nahradila současný dev box: 2 GB RAM v E6550 Core2 Duo); to umožní, aby repro havárii způsobující mis-chování, když běží pod silným ladění prostředí; nebo
  2. Přepsat operátorů newa deletevyužívat VirtualAlloca VirtualProtectoznačit paměť pouze pro čtení, jakmile se to dělá s. Spustit pod MSVC6a mít OS chytit Bad-chlap, který se při zápisu do uvolněné paměti. Ano, je to znamením zoufalství: Kdo to sakra přepisuje newa delete?! Zajímalo by mě, jestli to bude dělat to co nejpomaleji za Purify et al.

A ne: Zásilka s Purify přístrojovou postavena v roce nepřipadá v úvahu.

Kolega právě prošel kolem a zeptal se „přetečení zásobníku? Jsme stále stack teď přetéká?!?“

A teď je otázka: Jak mohu najít haldy Corruptor?


Aktualizovat: vyvážení new[]a delete[]zdá se, že dostal za sebou dlouhou cestu k vyřešení problému. Namísto 15 min, aplikace jde nyní asi dvě hodiny před shazovat. Není tam dosud. Jakékoliv další návrhy? Poškození haldy přetrvává.

Aktualizace: uvolnění build pod Visual Studio 2008 se zdá výrazně lepší; Současná podezření opírá o STLrealizaci, který je dodáván s VS98.


  1. Problém reprodukovat. Dr Watsonbude produkovat výpis, které by mohly být užitečné v další analýze.

Vezmu si na vědomí, ale já jsem znepokojen tím, že Dr. Watson bude aktivován pouze po faktu, nikoli když je haldy stále dupl na.

Další pokus by mohlo být použití WinDebugjako ladící nástroj, který je velmi silný, že zároveň také lehký.

Mám to jde v této chvíli znovu: není moc pomoci, dokud se něco pokazí. Chci zachytit vandal při činu.

Možná, že tyto nástroje vám umožní alespoň zúžit problém do určité složky.

I nemají velkou naději, ale zoufalé časy volají po ...

A jste si jisti, že všechny komponenty projektu mají správné nastavení runtime knihovny ( C/C++ tabkategorie generování kódu ve VS nastavení projektu 6,0)?

Ne nejsem, a strávím pár hodin zítra prochází pracovní plochy (58 projektů v něm) a kontrolovat, že jsou všechny kompilace a propojení s příslušnými příznaky.


Aktualizace: To trvalo 30 sekund. Vyberte všechny projekty v Settingsdialogovém okně, zrušte výběr dokud nenajdete projekt (y), které nemají správné nastavení (všichni měli správné nastavení).

Položena 04/08/2008 v 08:30
zdroj uživatelem
V jiných jazycích...                            


15 odpovědí

hlasů
26

Moje první volba bude věnován haldy nástroj, jako je pageheap.exe .

Přepisování nové a mazat by mohlo být užitečné, ale to neznamená, chytat ALLOCS spáchané nižší úrovně kódu. Pokud je to, co chcete, lepší Objížďka v low-level alloc APIů pomocí Microsoft objížďky.

Také Sanity kontroly, jako je: ověření vaší knihoven run-time zápas (release vs. ladění, multi-threaded vs. jednovláknové, dll vs. statické lib), podívejte se na špatné Odstraní (např nehodící se smazat [], by mělo být používaný), ujistěte se, že nejste míchání a odpovídající vašim ALLOCS.

Zkuste také selektivně vypnout závity a vidět, když / pokud problém zmizí.

Co zásobník volání atd vypadat v době první výjimka?

Odpovězeno 04/08/2008 v 08:51
zdroj uživatelem

hlasů
11

Mám stejné problémy ve své práci (můžeme použít také VC6někdy). A není snadné řešení pro něj. Mám jen několik rad:

  • Zkuste s automatickým havárie skládky na výrobní zařízení (viz procesní dampr ). Moje zkušenost říká Dr. Watson je to ideální pro dumping.
  • Odstraňte veškerý úlovek (...) z kódu. Často skrývat závažné výjimky paměti.
  • Zkontrolujte, zda Advanced Windows ladění - existuje spousta skvělých tipů pro problémy, jako je ta vaše. Doporučuji to celým svým srdcem.
  • Používáte-li STLvyzkoušet STLPorta zkontrolovat staví. Neplatný iterátor jsou peklo.

Hodně štěstí. Problémy, jako je ta vaše nám trvat měsíce řešit. Buďte připraveni na to ...

Odpovězeno 06/08/2008 v 13:41
zdroj uživatelem

hlasů
8

Spustit původní aplikaci s ADplus -crash -pn appnename.exe Když je paměť problém objeví-up dostanete pěknou velkou skládku.

Můžete analyzovat výpis přijít na to, co místo v paměti byl poškozen. Pokud budete mít štěstí přepsání paměti je jedinečný řetězec můžete zjistit, odkud pochází. Pokud nejste štěstí, budete muset sáhnout hluboko do win32hromady a přijít na to, co bylo na Orignal paměťové vlastnosti. (haldy -x může pomoci)

Poté, co vědět, co se zpackané, můžete zúžit appverifier je s nimi nakládáno se speciálními nastaveními haldy. tedy můžete určit, co DLLsledovat, nebo to, co přidělení velikosti sledovat.

Doufejme, že to bude zrychlení sledování stačí chytit viníka.

Podle mých zkušeností, nikdy jsem potřeboval plný režim haldy ověřovatele, ale jsem strávil spoustu času analyzováním havárie skládky (y) a zdrojů prohlížení.

PS: můžete použít DebugDiag analyzovat výpisy. Je možné poukázat na DLLvlastnící poškozený haldy, a dá vám další podrobnosti užitečných.

Odpovězeno 16/09/2008 v 08:33
zdroj uživatelem

hlasů
7

Měli jsme docela štěstí psaním vlastních malloc a volné funkce. Ve výrobě, ale stačí zavolat standardní malloc a zdarma, ale v ladění, mohou dělat, co chcete. Máme také jednoduchý základní třídu, která nedělá nic, ale přepsat nové a odstranit operátory k použití těchto funkcí, pak jakákoliv třída napíšete jednoduše zdědit z této třídy. Pokud máte spoustu kódu, to může být velký úkol nahradit volání malloc a zdarma k novému malloc a zdarma (nezapomeňte realloc!), Ale z dlouhodobého hlediska je to velmi užitečné.

V Steve Maguire knihy Psaní Solid kód (vysoce doporučeno), existují příklady ladění věcí, které můžete udělat v těchto rutin, jako jsou:

  • Sledujte přídělů najít netěsnosti
  • Přidělit více paměti, než je nutné a dát značky na začátku a na konci paměti - při volném rutiny, můžete zajistit, aby tyto znaky jsou stále tam
  • memset paměti se značkou na alokaci (najít využití neinicializované paměti) a zdarma (najít využití free'd paměti)

Dalším dobrým nápadem je nikdy používat věci, jako je strcpy, strcatnebo sprintf- vždy používat strncpy, strncata snprintf. Napsali jsme naše vlastní verze těchto také, aby se ujistil, nemáme odepsat konec vyrovnávací paměti, a ty se dostali spoustu problémů taky.

Odpovězeno 22/08/2008 v 18:11
zdroj uživatelem

hlasů
4

Ty by měly zaútočit na tento problém jak s runtime a statickou analýzu.

Pro statickou analýzu zvážit kompilace PREfast ( cl.exe /analyze). Zjistí neodpovídající deletea delete[], přetečení vyrovnávací paměti a řadu dalších problémů. Být připraven, když brodit mnoho kilobajtů L6 varování, a to zejména, pokud váš projekt stále ještě L4není stanovena.

PREfast je k dispozici s Visual Studio Team System a zřejmě jako součást Windows SDK.

Odpovězeno 12/10/2008 v 22:55
zdroj uživatelem

hlasů
3

Je to v nedostatku paměti? Pokud tomu tak je, že to může být, že nová vrací NULLspíše než házet std :: bad_alloc. Starší VC++překladače řádně neprovádí to. Tam je článek o Legacy selhání přidělení paměti zřítilo STLaplikací vytvořených pomocí VC6.

Odpovězeno 02/09/2008 v 07:03
zdroj uživatelem

hlasů
3

Zdánlivá náhodnost poškození paměti zní velmi podobně jako problému synchronizace závit - chyba je reprodukován v závislosti na rychlosti stroje. Pokud objekty (chuncks paměti) jsou sdíleny mezi závity a synchronizace (kritická sekce, mutex, semafor, ostatní) primitiva nejsou na per-třídy (per-objekt, na třídě) základ, pak je možné dojít k situaci, kde je odstraněn třída (kus paměti) / uvolněno během používání, nebo použit po odstraněn / uvolněno.

Jako test na to, že byste mohli přidat synchronizační primitiva pro každou třídu a metody. To umožní, aby váš kód pomalejší, protože mnohé objekty budou muset počkat na sebe, ale pokud to eliminuje poškození haldy, bude váš haldy proti korupci problém stal optimalizace kódu jeden.

Odpovězeno 25/08/2008 v 20:55
zdroj uživatelem

hlasů
1

Pokud se rozhodnete přepsat nové / odstranit, jsem udělal to a mají jednoduchý zdrojový kód na:

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

To zachytí úniky paměti a také vloží údaje stráže před a po bloku paměti zachytit poškození haldy. Stačí integrovat s ním tím, že #include „debug.h“ v horní části každého souboru CPP a definování DEBUG a DEBUG_MEM.

Odpovězeno 17/09/2008 v 14:40
zdroj uživatelem

hlasů
1

Takže z omezené informace, které máte, může to být kombinace jednoho nebo více věcí:

  • Bad využití haldy, tedy dvojité osvobozuje, čtou po volném, psát po volném, nastavení HEAP_NO_SERIALIZE vlajku s ALLOCS a zbaví více vláken ve stejném haldy
  • Nedostatek paměti
  • Bad kódu (tj přetečení vyrovnávací paměti, podtečení bufferu, atd)
  • „časování“ Problémy

Pokud je to vůbec první dva, ale ne poslední, měli byste se dostali ji teď buď pageheap.exe.

Které s největší pravděpodobností znamená, že je to kvůli tomu, jak je kód přístupu sdílenou paměť. Bohužel, sledování, která se bude dosti bolestivé. Nesynchronizované přístup do sdílené paměti se často projevuje jako podivné „načasování“ problémy. Věci jako nepoužívají sémantiku získávají / uvolnění pro synchronizaci přístupu ke sdílené paměti s příznakem, nepoužívá zámky odpovídajícím způsobem, atd.

Přinejmenším by to pomoci, aby bylo možné sledovat přidělení nějakým způsobem, jak bylo navrženo dříve. Nejméně pak si můžete prohlédnout, co se skutečně stalo, až do poškození haldy a pokusit diagnostikovat z toho.

Také, pokud můžete snadno přesměrovat přídělů na více hromad, možná budete chtít zkusit a uvidíte, zda to buď řeší problém nebo za následek více reprodukovatelné chování buggy.

Když jste testování s VS2008, jste spustit s HeapVerifier s Conserve paměti nastavena na hodnotu Ano? To by mohlo snížit vliv na výkon haldy alokátor. (Plus, budete muset spustit s ním Debug-> Spustit s Application Verifier, ale už možná víte, že).

Můžete také zkusit ladění s WinDbg a různé možnosti použití příkazu haldy!.

MSN

Odpovězeno 22/08/2008 v 17:51
zdroj uživatelem

hlasů
0

Pár námětů. Zmínil jste se hojná upozornění na W4 - Navrhoval bych si udělali čas na opravu svůj kód kompilovat čistě na úrovni varování 4 - to bude trvat ještě dlouhou cestu k prevenci subtilní těžké najít chyby.

Za druhé - pro / analyzovat přepínače - to skutečně generovat hojná varování. Chcete-li použít tento přepínač v mém projektu, to, co jsem udělal, bylo vytvořit nový hlavičkový soubor, který používal #pragma varování vypnout všechna další varování generované / analyzovat. Pak dál do souboru, zapnu jen ty varování mi záleží. Pak použijte přepínač / FI kompilátor vynutit tento soubor záhlaví, které mají být zahrnuty jako první ve všech svých kompilačních jednotek. To by vám mělo umožnit použít / analyzovat přepínač během vykonávanie výstup

Odpovězeno 03/10/2009 v 17:48
zdroj uživatelem

hlasů
0

Myslíte si, že se jedná o spor? Jsou více vláken sdílet jednu hromadu? Můžete dát každé vlákno vlastní hromadu s HeapCreate, pak může běžet rychle s HEAP_NO_SERIALIZE. V opačném případě, haldy by měla být závit bezpečné, pokud používáte multi-threaded verze systémových knihoven.

Odpovězeno 30/07/2009 v 14:48
zdroj uživatelem

hlasů
0

Ten malý, když jsem musel řešit podobný problém. Pokud problém stále existuje, doporučuji si to následujícím způsobem: Monitor všechny hovory do nové / odstranit a malloc / calloc / realloc / zdarma. Dělám jediné DLL export funkce pro evidenci všech hovorů. Tato funkce přijímat parametr pro identifikaci svůj zdrojový kód, ukazatel na přidělené oblasti a druhu spoření tuto informaci v tabulce hovoru. Všechny přidělené / uvolněno pár je vyloučen. Na konci nebo po něm budete potřebovat budete volat na jinou funkci pro vytvoření sestavy pro levou dat. S tímto můžete určit špatné hovory (nová / volné nebo malloc / smazat) nebo chybí. Pokud máte jakýkoli případ vyrovnávací paměti přepsány v kódu informace uloženy může být špatně, ale každý test může detekovat / objevit / include řešení selhání identifikovat. Mnoho běží pomůže identifikovat chyby. Hodně štěstí.

Odpovězeno 19/12/2008 v 12:52
zdroj uživatelem

hlasů
0

Graeme je návrh na zakázku malloc / free je to dobrý nápad. Uvidíme, jestli můžete charakterizovat nějaký vzor, ​​o korupci, aby vám rukojeti páky.

Například, pokud je vždy v bloku stejné velikosti (řekněme 64 bytů), pak změnit svůj malloc / volný pár vždy přidělí 64 bajtů kousky ve vlastní straně. Když se uvolní 64 byte kus pak nastavte bity ochrany paměti na této straně, aby se zabránilo čtení a wites (pomocí VirtualQuery). Potom někdo pokusu o přístup k této paměti vygeneruje výjimku, nikoli poškozením haldy.

To ovšem předpokládá, že počet nevyřízených 64 bytových bloků je pouze mírná, nebo máte hodně paměti spalovat v krabici!

Odpovězeno 02/09/2008 v 05:23
zdroj uživatelem

hlasů
0

Moje první akce by takto:

  1. Vybudovat binární soubory v „Release“ verze, ale vytváření ladicí info soubor (najdete tuto možnost v nastavení projektu).
  2. Použít Dr. Watson jako ladicí defualt (drwtsn32 -I) na stroji, na kterém chcete problém reprodukovat.
  3. Repdroduce problém. Dr. Watson bude produkovat výpis, které by mohly být užitečné v další analýze.

Další pokus by mohlo být použití WinDebug jako ladící nástroj, který je velmi silný, že zároveň také lehký.

Možná, že tyto nástroje vám umožní alespoň zúžit problém do určité složky.

A jste si jisti, že všechny komponenty projektu mají správné nastavení runtime knihovny (C / C ++ kartu, kategorie generování kódu ve VS nastavení projektu 6,0)?

Odpovězeno 04/08/2008 v 09:26
zdroj uživatelem

hlasů
0

Zkoušel jsi starý buduje, ale tam je důvod, proč nemůžete pokračovat dál zpět v historii repozitáře a vidět přesně to, kdy byla zavedena chyba?

V opačném případě bych doporučil přidat jednoduchý záznam nějakého druhu pomoci vystopovat problém, když jsem v rozpacích z toho, co konkrétně budete chtít přihlásit.

Pokud můžete zjistit, co přesně mohou způsobit tento problém, přes google a dokumentace výjimek jste získali, možná, že bude dávat další poznatky o tom, co hledat v kódu.

Odpovězeno 04/08/2008 v 08:48
zdroj uživatelem

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