Vra

Ek werk aan 'n veeldraad C++-toepassing wat die hoop beskadig.Die gewone instrumente om hierdie korrupsie op te spoor blyk ontoepasbaar te wees.Ou weergawes (18 maande oud) van die bronkode vertoon dieselfde gedrag as die mees onlangse vrystelling, so dit bestaan ​​al lank en is net nie opgemerk nie;aan die nadeel, bron delta's kan nie gebruik word om te identifiseer wanneer die fout ingestel is nie - daar is baie van kodeveranderings in die bewaarplek.

Die aansporing vir ineenstortingsgedrag is om deurset in hierdie stelsel te genereer - sokoordrag van data wat in 'n interne voorstelling ingeskakel word.Ek het 'n stel toetsdata wat van tyd tot tyd die toepassing sal laat uitsonder (verskeie plekke, verskeie oorsake - insluitend hooptoewysing wat misluk, dus:hoop korrupsie).

Die gedrag blyk verband te hou met SVE krag of geheue bandwydte;hoe meer van elk die masjien het, hoe makliker is dit om te crash.Deaktiveer 'n hiper-threading kern of 'n dubbel-kern kern verminder die koers van (maar elimineer nie) korrupsie.Dit dui op 'n tydsberekeningverwante kwessie.

Nou hier is die vryf:
Wanneer dit onder 'n ligte ontfoutomgewing gebruik word (sê Visual Studio 98 / AKA MSVC6) die hoop korrupsie is redelik maklik om te reproduseer - tien of vyftien minute verloop voordat iets gruwelik misluk en uitsonderings, soos 'n alloc; wanneer jy onder 'n gesofistikeerde ontfoutomgewing hardloop (Rational Purify, VS2008/MSVC9 of selfs Microsoft Application Verifier) ​​word die stelsel geheue-spoedgebonde en val nie ineen nie (Geheue-gebonde:SVE kom nie bo nie 50%, skyfliggie is nie aan nie, die program gaan so vinnig dit kan, boks verbruik 1.3G van 2G RAM).Dus, Ek het 'n keuse tussen om die probleem te kan reproduseer (maar nie die oorsaak te identifiseer nie) of om die oorsaak te kan identifiseer of 'n probleem wat ek nie kan reproduseer nie.

My huidige beste raaiskoot oor waar om volgende is:

  1. Kry 'n waansinnig knorrige boks (om die huidige dev-boks te vervang:2 Gb RAM in 'n E6550 Core2 Duo);dit sal dit moontlik maak om die ongeluk wat wangedrag veroorsaak te herhaal wanneer dit onder 'n kragtige ontfoutomgewing uitgevoer word;of
  2. Herskryf operateurs new en delete te gebruik VirtualAlloc en VirtualProtect om geheue as slegs-lees te merk sodra dit klaar is.Hardloop onder MSVC6 en laat die OS die slegte ou vang wat na die vrygestelde geheue skryf.Ja, dit is 'n teken van desperaatheid:wie de hel herskryf new en delete?!Ek wonder of dit dit so stadig gaan maak soos onder Purify et al.

En nee:Versending met Purify-instrumentasie ingebou is nie 'n opsie nie.

'n Kollega het net verbygestap en gevra "Stack Overflow?Kry ons nou stapel oorloop?!?"

En nou, die vraag: Hoe vind ek die heap corruptor op?


Opdateer:balanseer new[] en delete[] blykbaar 'n lang pad om die probleem op te los.In plaas van 15 minute, gaan die toepassing nou ongeveer twee uur voordat dit neerstort.Nog nie daar nie.Enige verdere voorstelle?Die hoop korrupsie duur voort.

Opdateer:'n vrystelling wat onder Visual Studio 2008 gebou is, lyk dramaties beter;huidige vermoede berus op die STL implementering wat saam met VS98.


  1. Reproduseer die probleem. Dr Watson sal 'n storting produseer wat nuttig kan wees in verdere ontleding.

Ek sal daarvan kennis neem, maar ek is bekommerd dat dr Watson eers ná die tyd gestruikel sal word, nie wanneer die hoop getrap word nie.

Nog 'n poging gebruik dalk WinDebug as 'n ontfoutingsinstrument wat redelik kragtig is en terselfdertyd ook liggewig is.

Het dit op die oomblik weer aan die gang:nie veel hulp totdat iets verkeerd loop nie.Ek wil die vandal op heterdaad betrap.

Miskien sal hierdie instrumente jou ten minste toelaat om die probleem tot sekere komponent te beperk.

Ek het nie veel hoop nie, maar desperate tye vra vir...

En is jy seker dat al die komponente van die projek die korrekte runtime-biblioteekinstellings het (C/C++ tab, Kodegenerering-kategorie in VS 6.0-projekinstellings)?

Nee, ek is nie, en ek sal môre 'n paar uur spandeer om deur die werkspasie (58 projekte daarin) te gaan en te kyk of hulle almal saamstel en met die toepaslike vlae koppel.


Opdateer:Dit het 30 sekondes geneem.Kies alle projekte in die Settings dialoog, ontkies totdat jy die projek(te) kry wat nie die regte instellings het nie (hulle het almal die regte instellings gehad).

Was dit nuttig?

Oplossing

My eerste keuse sou 'n toegewyde hoop instrument wees soos pageheap.exe.

Om nuut te herskryf en uit te vee, kan nuttig wees, maar dit vang nie die toekennings wat deur laervlakkode toegepas word nie.As dit is wat jy wil hê, beter om die omweg low-level alloc APIs met behulp van Microsoft Detours.

Ook gesondheidsondersoeke soos:verifieer dat u looptydbiblioteke ooreenstem (vrystelling vs.ontfout, multi-draad vs.enkeldraad, dll vs.static lib), soek slegte deletes (bv. verwyder waar delete [] gebruik moes gewees het), maak seker dat jy nie jou allocs meng en pas nie.

Probeer ook om drade selektief af te skakel en kyk wanneer/of die probleem weg is.

Hoe lyk die oproepstapel ens ten tyde van die eerste uitsondering?

Ander wenke

Ek het dieselfde probleme in my werk (ons gebruik ook VC6 soms).En daar is geen maklike oplossing daarvoor nie.Ek het net 'n paar wenke:

  • Probeer met outomatiese ongelukstortings op produksiemasjien (sien Proses Dumper).My ervaring sê dr.Watson is nie perfek nie vir storting.
  • Verwyder alle vang(...) vanaf jou kode.Hulle verberg dikwels ernstige geheue-uitsonderings.
  • Tjek Gevorderde Windows-ontfouting - daar is baie goeie wenke vir probleme soos joune.Ek beveel dit met my hele hart aan.
  • As jy gebruik STL probeer STLPort en gekontroleerde geboue.Ongeldige iterator is hel.

Sterkte.Probleme soos joune neem ons maande om op te los.Wees gereed hiervoor...

Begin die oorspronklike toepassing met ADplus -crash -pn appnename.exeWanneer die geheueprobleem opduik, sal jy 'n lekker groot storting kry.

U kan die stortingsterrein ontleed om vas te stel watter geheueligging beskadig is.As jy gelukkig is, is die oorskryf geheue 'n unieke string wat jy kan uitvind waar dit vandaan kom.As jy nie gelukkig is nie, sal jy moet delf in win32 hoop en bereken wat die oorspronklike geheue-eienskappe was.(hoop -x kan dalk help)

Nadat jy geweet het wat deurmekaar was, kan jy die gebruik van die appverifierer met spesiale hoopinstellings beperk.d.w.s.jy kan spesifiseer wat DLL jy monitor, of watter toewysingsgrootte om te monitor.

Hopelik sal dit die monitering genoeg bespoedig om die skuldige vas te trek.

In my ervaring het ek nooit 'n volledige hoop-verifikasiemodus nodig nie, maar ek het baie tyd spandeer om die ongelukstorting(s) te ontleed en bronne te blaai.

P.S:Jy kan gebruik DebugDiag om die stortingsterreine te ontleed.Dit kan wys op die DLL die besit van die korrupte hoop, en gee jou ander nuttige besonderhede.

Ons het baie geluk gehad deur ons eie malloc en gratis funksies te skryf.In produksie noem hulle net die standaard malloc en gratis, maar in ontfouting kan hulle doen wat jy wil.Ons het ook 'n eenvoudige basisklas wat niks anders doen as om die nuwe operateurs te ignoreer en te verwyder om hierdie funksies te gebruik nie, dan kan enige klas wat jy skryf eenvoudig van daardie klas af erf.As jy 'n klomp kode het, kan dit 'n groot taak wees om oproepe na malloc te vervang en gratis na die nuwe malloc en gratis (moenie van realloc vergeet nie!), maar op die lang termyn is dit baie nuttig.

In Steve Maguire se boek Skryf soliede kode (sterk aanbeveel), daar is voorbeelde van ontfouting goed wat jy in hierdie roetines kan doen, soos:

  • Bly op hoogte van toekennings om lekkasies te vind
  • Ken meer geheue toe as wat nodig is en plaas merkers aan die begin en einde van geheue -- tydens die gratis roetine kan jy verseker dat hierdie merkers steeds daar is
  • memset die geheue met 'n merker op toekenning (om gebruik van ongeïnitialiseerde geheue te vind) en op vry (om gebruik van vrye geheue te vind)

Nog 'n goeie idee is om nooit gebruik dinge soos strcpy, strcat, of sprintf -- gebruik altyd strncpy, strncat, en snprintf.Ons het ook ons ​​eie weergawes hiervan geskryf om seker te maak dat ons nie die einde van 'n buffer afskryf nie, en dit het ook baie probleme opgedoen.

U moet hierdie probleem aanval met beide looptyd en statiese analise.

Vir statiese ontleding oorweeg dit om saam te stel met PREfast (cl.exe /analyze).Dit bespeur ongelyke delete en delete[], bufferoorskryding en 'n magdom ander probleme.Wees egter voorbereid om deur baie kilogrepe se L6-waarskuwing te gaan, veral as jou projek nog het L4 nie reg.

PREfast is beskikbaar met Visual Studio Team System en, blykbaar, as deel van Windows SDK.

Die oënskynlike ewekansigheid van die geheue-korrupsie klink baie soos 'n draadsinchronisasieprobleem - 'n fout word gereproduseer afhangende van die masjienspoed.As voorwerpe (brokkies geheue) tussen drade gedeel word en sinchronisasie (kritiese seksie, mutex, semafoor, ander) primitiewe is nie op per-klas (per-voorwerp, per-klas) basis nie, dan is dit moontlik om by 'n situasie te kom. waar klas (stuk geheue) uitgevee / vrygemaak word terwyl dit gebruik word, of gebruik word nadat dit uitgevee / vrygemaak is.

As 'n toets daarvoor, kan u sinchronisasie-primitiewe by elke klas en metode voeg.Dit sal jou kode stadiger maak omdat baie voorwerpe vir mekaar sal moet wag, maar as dit die hoopkorrupsie uitskakel, sal jou hoopkorrupsieprobleem 'n kode-optimeringsprobleem word.

Is dit in lae geheue toestande?As dit so is, kan dit wees dat nuwe terugkeer NULL eerder as om std::bad_alloc te gooi.Ouer VC++ samestellers het dit nie behoorlik geïmplementeer nie.Daar is 'n artikel oor Verouderde geheuetoewysingsfoute verongeluk STL programme gebou met VC6.

Jy het ou geboue probeer, maar is daar 'n rede waarom jy nie verder kan teruggaan in die bewaarplekgeskiedenis en presies kan sien wanneer die fout bekendgestel is nie?

Andersins sou ek voorstel dat u 'n eenvoudige logboek van een of ander aard byvoeg om die probleem op te spoor, alhoewel ek nie weet wat u spesifiek wil aanteken nie.

As jy kan uitvind wat presies hierdie probleem KAN veroorsaak, via google en dokumentasie van die uitsonderings wat jy kry, sal dit dalk verdere insig gee oor waarna om in die kode te soek.

My eerste aksie sou soos volg wees:

  1. Bou die binaries in "Release"-weergawe, maar skep 'n debug-inligtinglêer (jy sal hierdie moontlikheid in projekinstellings vind).
  2. Gebruik Dr Watson as 'n standaard ontfouter (DrWtsn32 -I) op 'n masjien waarop jy die probleem wil reproduseer.
  3. Herstel die probleem.Dr Watson sal 'n stortingsterrein produseer wat nuttig kan wees in verdere ontleding.

Nog 'n poging kan WinDebug gebruik as 'n ontfoutingsinstrument wat nogal kragtig is en terselfdertyd ook liggewig is.

Miskien sal hierdie instrumente jou ten minste toelaat om die probleem tot sekere komponent te beperk.

En is jy seker dat al die komponente van die projek die korrekte runtime-biblioteekinstellings het (C/C++-oortjie, kodegenerering-kategorie in VS 6.0-projekinstellings)?

So uit die beperkte inligting wat jy het, kan dit 'n kombinasie van een of meer dinge wees:

  • Slegte hoop gebruik, d.w.s. dubbel vrystellings, lees na vry, skryf na vry, stel die HEAP_NO_SERIALIZE vlag met allocs en vry van veelvuldige drade op dieselfde hoop
  • Uit geheue
  • Slegte kode (d.w.s. buffer oorloop, buffer ondervloei, ens.)
  • "Tydsberekening" kwessies

As dit enigsins die eerste twee is, maar nie die laaste nie, moes jy dit nou met óf pageheap.exe gevang het.

Wat heel waarskynlik beteken dat dit te wyte is aan hoe die kode toegang tot gedeelde geheue verkry.Ongelukkig gaan dit nogal pynlik wees om dit op te spoor.Ongesinchroniseerde toegang tot gedeelde geheue manifesteer dikwels as vreemde "tydsberekening"-kwessies.Dinge soos om nie die verkryging/vrystelling semantiek te gebruik om toegang tot gedeelde geheue met 'n vlag te sinchroniseer nie, om nie slotte toepaslik te gebruik nie, ens.

Dit sal ten minste help om toekennings op een of ander manier te kan naspoor, soos vroeër voorgestel is.Ten minste dan kan jy sien wat werklik gebeur het tot die hoop korrupsie en probeer om daaruit te diagnoseer.

Ook, as jy maklik toewysings na veelvuldige hope kan herlei, wil jy dit dalk probeer om te sien of dit óf die probleem oplos óf lei tot meer reproduseerbare karretjiegedrag.

Toe jy met VS2008 getoets het, het jy met HeapVerifier gehardloop met Conserve Memory op Ja gestel?Dit kan die prestasie-impak van die hooptoewyser verminder.(Plus, jy moet daarmee hardloop Ontfout->Begin met Application Verifier, maar jy weet dit dalk reeds.)

Jy kan ook probeer ontfout met Windbg en verskeie gebruike van die !heap-opdrag.

MSN

As jy kies om nuwe/vee te herskryf, het ek dit gedoen en het 'n eenvoudige bronkode by:

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

Dit vang geheuelekkasies op en voeg ook wagdata voor en na die geheueblok in om hoopkorrupsie vas te lê.Jy kan net daarmee integreer deur #include "debug.h" boaan elke CPP-lêer te plaas, en DEBUG en DEBUG_MEM te definieer.

Graeme se voorstel van pasgemaakte malloc/gratis is 'n goeie idee.Kyk of jy 'n patroon oor die korrupsie kan karakteriseer om jou 'n handvatsel te gee om te benut.

Byvoorbeeld, as dit altyd in 'n blok van dieselfde grootte is (sê 64 grepe), verander dan jou malloc/vry-paar om altyd 64 grepe-stukke in hul eie bladsy toe te ken.Wanneer jy 'n 64 grepe-stuk vrystel, stel dan die geheuebeskermingsstukke op daardie bladsy om lees en wites te voorkom (met VirtualQuery).Dan sal enigiemand wat probeer om toegang tot hierdie geheue te verkry, 'n uitsondering genereer eerder as om die hoop te beskadig.

Dit aanvaar wel dat die aantal uitstaande 64 grepe stukke slegs matig is of jy het baie geheue om in die boks te verbrand!

Die bietjie tyd wat ek gehad het om 'n soortgelyke probleem op te los.As die probleem steeds bestaan, stel ek voor dat jy dit doen:Monitor alle oproepe na nuwe/vee en malloc/calloc/realloc/gratis.Ek maak 'n enkele DLL wat 'n funksie uitvoer om alle oproepe te registreer.Hierdie funksie ontvang parameter vir die identifisering van jou kode bron, wyser na toegekende area en tipe oproep stoor hierdie inligting in 'n tabel.Alle toegekende/vrygestelde paar word uitgeskakel.Aan die einde of nadat jy nodig het, maak jy 'n oproep na 'n ander funksie vir die skep van verslag vir links data.Hiermee kan jy verkeerde oproepe (nuut/gratis of malloc/vee) of ontbreek identifiseer.As enige geval van buffer in jou kode oorgeskryf is, kan die inligting wat gestoor is verkeerd wees, maar elke toets kan 'n oplossing van geïdentifiseerde mislukking opspoor/ontdek/insluit.Baie lopies om die foute te help identifiseer.Sterkte.

Dink jy dit is 'n rastoestand?Deel verskeie drade een hoop?Kan jy elke draad 'n privaat hoop gee met HeapCreate, dan kan hulle vinnig hardloop met HEAP_NO_SERIALIZE.Andersins moet 'n hoop draad veilig wees as jy die multi-threaded weergawe van die stelsel biblioteke gebruik.

'n Paar voorstelle.Jy noem die oorvloedige waarskuwings by W4 - ek sal voorstel dat jy die tyd neem om jou kode reg te maak om skoon op waarskuwingsvlak 4 saam te stel - dit sal baie help om subtiele moeilik opspoorbare foute te voorkom.

Tweedens - vir die /analyze-skakelaar - genereer dit inderdaad oorvloedige waarskuwings.Om hierdie skakelaar in my eie projek te gebruik, wat ek gedoen het, was om 'n nuwe koplêer te skep wat #pragma-waarskuwing gebruik het om al die bykomende waarskuwings wat deur /analyze gegenereer word, af te skakel.Dan verder af in die lêer skakel ek net daardie waarskuwings aan waarvoor ek omgee.Gebruik dan die /FI-samestellerskakelaar om hierdie koplêer te dwing om eerste by al jou samestellingseenhede ingesluit te word.Dit behoort jou in staat te stel om die /analyze-skakelaar te gebruik terwyl jy die uitset beheer

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top