[C++]Heap overrun

Pagina: 1
Acties:

  • Rukapul
  • Registratie: Februari 2000
  • Laatst online: 00:08
Ik zit al enige weken met het probleem dat in een stuk code dat ik geschreven heb zo af en toe een overrun op een datastructuur op de heap plaatsvindt, wat een waarschuwing (assert in de 'free' code van VC) danwel crash oplevert (tja, er wordt toch wat nuttige data overschreven :P).

Het daadwerkelijke probleempunt kan ik echter maar niet vinden:
- ik heb 2 testen waarbij het probleem reproduceerbaar is in het merendeel van de keren dat ik ze executeer
- in de 'productie' code heb ik er geen last van terwijl het gebruik daar nauwelijks afwijkt van de 2 testen. Er wordt dan echter van een echte file gelezen ipv een stub, wat invloed heeft op de timing.
- onder Linux treedt het probleem niet op (althans geen warning/crash), terwijl het onder Windows (VC6) met grote regelmaat reproduceerbaar is
- het geheel draait in een aantal threads zodat timing essentieel is
- bij debuggen in step mode treedt het probleem niet op (timing?)
- de fout komt vrijwel altijd bovendrijven bij dezelfde delete operatie (waar op zich zelf niets mis mee is, er gaat een VC assert af)

Ik ben al met Numega DevPartner bezig geweest en die geeft wel aan dat er een overrun plaatsvindt, maar 'te laat' zodat ik nog niet weet waar het stuk geheugen nou overschreven wordt. (Bij deze check controleert devpartner of een paar controlebytes na elk block niet overschreven zijn bij een delete en nog wat andere memory zaken.)
Devpartner ondersteunt ook een zgn adaptive analysis die vaker de controle bytes controleert, maar dat levert ook niets bruikbaars op.
De zwaarste check van Devpartner levert ook niets bruikbaars op en kan bovendien niet vaak gebruikt worden aangezien deze veels te traag werkt (onbruikbaar traag zelfs).

Ik heb ook op een heleboel plaatsen al assert(_heapchk() == _HEAPOK) ingevoegd, maar dat werkt ook niet om het probleem te localiseren. Het komt zelfs voor dat een regel na de assert, met de betreffende delete, een fout rapporteert terwijl de assert geldig is.

Lang verhaal, maar korte vraag: heeft iemand een idee wat voor een andere tool(s) of technieken ik kan gebruiken om overrun(s) eruit te halen. Ik ben eigenlijk maar een prutser die zo goed mogelijk dmv tools, tfm, en google dit probeert te fixen, maar ben benieuwd hoe een prof pw-er dit aanpakt :)

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Probeer ook eens http://www.automatedqa.com/products/aqtime.asp. Daar heb ik goede ervaringen mee.

We adore chaos because we like to restore order - M.C. Escher


  • demonite
  • Registratie: April 2000
  • Laatst online: 29-05 08:55

demonite

the way is up

in de 'productie' code heb je er geen last van zeg je ?
bedoel je daarmee een "release-mode" compilatie ?

if so: dan kan het zijn dat je verschillende runtime environments aan het mengen bent.. msvcrt en msvcrtd.

dat breakpoint waar je het over hebt wordt zeker aangegeven met "user breakpoint reached"

Zo'n verschijnsel heb ik nml ook op het werk.
Het komt dus omdat 1 of meerdere libraries in je debug build geen debug build is maar een release build... Zo hebben wij op het werk een library aangeleverd gekregen voor license checking en dergelijke..

Anyway, wij maken er ons niet druk over.. Het is wat annoying maar we weten waar het door komt.. En like you said, in release mode boeit het niet.

Alleen een klein verschilletje met jouw situatie, bij ons crasht het niet.. Het is alleen wat annoying die user breakpoints, gelukkig treden ze niet zo vaak op.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Of Rational Purify, maar die is niet gratis, en ook niet goedkoop

[ Voor 61% gewijzigd door .oisyn op 17-07-2003 22:52 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Rukapul
  • Registratie: Februari 2000
  • Laatst online: 00:08
Eens rondgekeken, evaluatie versie gedownload. Maar vrees dat zo'n tool wel weer een leercurve heeft. Weet iemand waarin deze tool verschilt van Devpartner studio van numega?
demonite schreef op 17 juli 2003 @ 22:34:
in de 'productie' code heb je er geen last van zeg je ?
bedoel je daarmee een "release-mode" compilatie ?
Nee, ik bedoel niet release code. (hoewel ik de testen nooit in release mode heb gedraaid) Gewoon bijna hetzelfde stukje code maar dan 1 stub vervangen door echte code (de stub is bovendien zo klein dat daar eenvoudig aan te tonen is dat daar niet de overrun plaatsvindt).
if so: dan kan het zijn dat je verschillende runtime environments aan het mengen bent.. msvcrt en msvcrtd.
Zou kunnen, maar dan verwacht ik het altijd en niet alleen maar in 2 gevallen. Overigens bouw ik altijd in debug mode en zijn er hooguit wat externe libraries in release mode gebouwd. Eens zien of ik een release build kan bouwen en testen.
dat breakpoint waar je het over hebt wordt zeker aangegeven met "user breakpoint reached"
Yep. Maar dat user breakpoint wordt bereikt in een stuk 'assert' code van VC, dus dat is logisch in debug mode. (Breek me de bek trouwens niet los over user breakpoints. Ik heb op het punt gestaan om handmatig ntddl.dll te patchen om die 'int 3' te vervangen door 'nop' omdat een QT applicatie nauwelijks te debuggen is onder Devpartner studio omdat bijna elke schermupdate ervoor zorgt dat eerst een user breakpoint aangeroepen wordt en je in VC dat niet kunt stoppen en dus 'OK' en 'F5' moet drukken :X )
Zo'n verschijnsel heb ik nml ook op het werk.
Het komt dus omdat 1 of meerdere libraries in je debug build geen debug build is maar een release build... Zo hebben wij op het werk een library aangeleverd gekregen voor license checking en dergelijke..

Anyway, wij maken er ons niet druk over.. Het is wat annoying maar we weten waar het door komt.. En like you said, in release mode boeit het niet.
Het boeit me in zoverre dat we een test-first ontwikkelproces (a-la XP) hanteren en de testen MOETEN draaien en zeggen dat hij het doet in sommige gevallen is niet goed genoeg ;)
Alleen een klein verschilletje met jouw situatie, bij ons crasht het niet.. Het is alleen wat annoying die user breakpoints, gelukkig treden ze niet zo vaak op.
.oisyn schreef op 17 July 2003 @ 22:51:
[...]


Of Rational Purify, maar die is niet gratis, en ook niet goedkoop
Hmmm... Op de softwareboom waar ik op werk heeft iemand ook een Purify losgelaten volgens mij, maar daar bleken nog heel wat haken en ogen aan te zitten, o.a. een stijle leercurve. Vooralsnog heb ik zelf geen purify tot m'n beschikking.

Wellicht iemand die gewoon goede 'tips' heeft om het met m'n bestaande tools en wat handwerk op te lossen? Een strategie zegmaar, want het is me al wel duidelijk dat automatische tools dit niet zomaar op gaan lossen (hoewel ze al wel vele fouten geidentificeerd hebben :) )

[ Voor 17% gewijzigd door Rukapul op 18-07-2003 01:09 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mja, een algemene tip is natuurlijk defensief coden, maar daar is het nu te laat voor neem ik aan... of je moet alles gaan willen herschrijven ;)

Verder ondersteund windows data breakpoints, dus een breakpoint die optreedt als er op een bepaald adres wordt gelezen of geschreven. Je zou dan bij allocatie van geheugen een iets grotere buffer moeten alloceren, en dan vervolgens databreakpoints voorbij de originele buffergrootte moeten plaatsen. Ik heb alleen geen idee hoe je dat vanuit je programma kunt doen, ik kan er niets vinden in de MSDN erover

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • demonite
  • Registratie: April 2000
  • Laatst online: 29-05 08:55

demonite

the way is up

Hier gaat het ook altijd fout bij een delete.
En ook hier gebruiken we QT.

Ik zou zeggen, bouw eens in release mode en test dan daarmee.


Het clashen van runtime environments is een "bekend" probleem...

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
.oisyn schreef op 18 July 2003 @ 02:19:
Verder ondersteund windows data breakpoints, dus een breakpoint die optreedt als er op een bepaald adres wordt gelezen of geschreven. Je zou dan bij allocatie van geheugen een iets grotere buffer moeten alloceren, en dan vervolgens databreakpoints voorbij de originele buffergrootte moeten plaatsen. Ik heb alleen geen idee hoe je dat vanuit je programma kunt doen, ik kan er niets vinden in de MSDN erover
Ik weet van NuMega SoftIce dat je hiermee data breakpoints kunt zetten. Ik weet alleen niet of hier ook een evaluatieversie van bestaat....

  • demonite
  • Registratie: April 2000
  • Laatst online: 29-05 08:55

demonite

the way is up

Data breakpoints kun je ook met Visual studio zetten...
Netzoals conditional breakpoints..

Maar daar heb je in dit geval niets aan vermoed ik want het is niet op te lossen dmv coderen. Tenminste, ik ga er even van uit dan zijn probleem het clashen van veschillende runtime environments is.

http://support.microsoft.com/default.aspx?scid=kb;[LN];94248

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

MrBucket schreef op 18 juli 2003 @ 14:27:
Ik weet van NuMega SoftIce dat je hiermee data breakpoints kunt zetten. Ik weet alleen niet of hier ook een evaluatieversie van bestaat....
ja, dat kan met de VC++ debugger ook, maar het gaat er nou juist om dat je dat zelf vanuit code moet kunnen doen

.edit: wat demonite zei dus |:(
note to self: draad lezen :P

Ik heb de topicstart trouwens nog eens goed doorgelezen. Ik zie nergens iets staan over gebruik van DLLs. Runtime clashes in een enkel project met statische libs kan niet, aangezien alle CRT namen hetzelfde zijn. Er kunnen dus 2 mogelijkheden zijn: er wordt data overschreven die niet overschreven hoort te worden, of je delete of free'd een ongeldige pointer (dus een pointer naar een stuk geheugen dat niet met new/malloc gealloceerd is, of je delete/free'd een stuk geheugen meerdere keren)

De oplossing kan heel simpel zijn door alle malloc/new calls te loggen, en te kijken of de free/delete calls corresponderen met de logs. Klopt dit allemaal, dan zit het probleem dus idd in foute pointer dereferencement, waardoor je geheugen buiten de valide buffer waar de pointer naar wijst aanpast

[ Voor 58% gewijzigd door .oisyn op 18-07-2003 15:17 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Rukapul
  • Registratie: Februari 2000
  • Laatst online: 00:08
.oisyn schreef op 18 July 2003 @ 15:09:
[...]


ja, dat kan met de VC++ debugger ook, maar het gaat er nou juist om dat je dat zelf vanuit code moet kunnen doen
Kan dit nu wel of juist niet? Ze handmatig zetten is op z'n zachtst gezegd erg lastig.
Ik heb de topicstart trouwens nog eens goed doorgelezen. Ik zie nergens iets staan over gebruik van DLLs. Runtime clashes in een enkel project met statische libs kan niet, aangezien alle CRT namen hetzelfde zijn.
De code is een bonte verzameling van DLL's en een stuk of 2 statische libs. Alle componenten die we zelf bouwen gebruiken dezelfde settings. Een paar 3rd party libs zouden evt zich anders kunnen gedragen, maar toch denk ik niet dat hier iets met de runtimes van VC wat fout gaat aangezien andere stukken code die voor 99% hetzelfde zijn (zelfde libs, etc.) het probleem niet vertonen.
Er kunnen dus 2
mogelijkheden zijn: er wordt data overschreven die niet overschreven hoort te worden, of je delete of free'd een ongeldige pointer (dus een pointer naar een stuk geheugen dat niet met new/malloc gealloceerd is, of je delete/free'd een stuk geheugen meerdere keren)

De oplossing kan heel simpel zijn door alle malloc/new calls te loggen, en te kijken of de free/delete calls corresponderen met de logs. Klopt dit allemaal, dan zit het probleem dus idd in foute pointer dereferencement, waardoor je geheugen buiten de valide buffer waar de pointer naar wijst aanpast
Bezig. Niet met de hand want daarvoor zijn de aantallen te groot maar wederom met de tool. Het vervelende is dat de fout alleen bij een integratietest voorkomt en er dus een flinke hoeveelheid code gedebugged moet worden.

Bedenk net nog een vraag. Als ik een memory locatie heb waar de overschrijving heeft plaatsgevonden, is er dan een mogelijkheid dat ik uit VS kan peuteren welke variabele naam, object, pointer daar/daarvoor/daarna heeft gestaan?

[ Voor 7% gewijzigd door Rukapul op 18-07-2003 16:11 ]


  • demonite
  • Registratie: April 2000
  • Laatst online: 29-05 08:55

demonite

the way is up

Op het moment dat die assert optreed... (ik neem even aan dat je het zaakje runt vanuit de debugger)

Dan zie je toch in de stacktrace welke delete het is ?


In mijn geval is dat iig zo... Maar wat er gedelete wordt is in mijn geval gewoon goed, want die pointer bevat wel degelijk de goede class... Toch krijg ik een RtlFreeHeap melding naar mijn hoofd geslingerd van VC.

Overigens kan je met je dependency viewer zien tegen welke runtime libraries je aanlinkt..


btw oisyn, ik weet ook niet alles.. Maar als ik .lib bouw (die ik dus idd statisch ga inlinken) in release mode en ik link die lib aan debug executable... Weet je dan zeker dat er niet 2 runtime libraries worden ingelinked?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

demonite schreef op 18 July 2003 @ 19:14:
btw oisyn, ik weet ook niet alles.. Maar als ik .lib bouw (die ik dus idd statisch ga inlinken) in release mode en ik link die lib aan debug executable... Weet je dan zeker dat er niet 2 runtime libraries worden ingelinked?
als je een .lib bouwt wordt er niet gelinked. Al je source files worden naar object files gecompiled, en die worden gearchiveerd naar een .lib. Er vindt dus geen linking plaats.
Pas op het moment dat je de lib gebruikt worden alle dependencies eruit gehaald. Oftewel, als er een unresolved external symbol is, dan kijkt de linker in alle libs of het symbol daar misschien in gedefinieerd is, en zo ja, dan wordt die ene object file waar het symbol in staat eruit gehaald en meegelinkt. Dit kan weer als gevolg hebben dat er weer andere unresolved external symbols optreden, en dit proces gaat door tot alle symbols resolved zijn. De runtime wordt dus pas meegelinkt op het moment dat je een executable (exe, dll) bouwt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1