2009-07-09 5 views
5

Ho avuto questo brutto bug che è scomparso in passato ma ora dopo un po 'di tempo è tornato.FastMM4 dice "L'intestazione del blocco è stata danneggiata"

Ho due oggetti TSam (derivati ​​da TPersistent) creati e caricati in un oggetto TAsmJob (derivato da TObjectList).

In fase di esecuzione, un modulo crea un TStringGrid e quindi l'AsmJob che crea questi due oggetti SAM (e carica alcuni dati dal disco in ciascuno di essi). Anche AsmJob è assegnato alla griglia. Quando il modulo viene distrutto, Grid si prende cura di AsmJob liberandolo, il che libera gli oggetti TSam. Ecco il problema: il primo oggetto viene liberato senza problemi, ma il secondo muore quando viene chiamato il suo metodo ereditato (in Destroy destructor).

Uso FreeAndNil nell'intero programma per liberare gli oggetti. Gli oggetti TSam non sono NIL !!!!! Quindi, questo è il primo tentativo di liberare gli oggetti. Anche i dati all'interno degli oggetti sono coerenti.

La spina dorsale del programma si presenta così:

**Create:** 

Form -> StringGrid 
    -> AsmJob -> Sam1, Sam2 
StringGrid.AsmJob:= AsmJob; 


**Free:** 

Form -> StringGrid -> AsmJob -> Sam1, Sam2 

Io davvero non capisco dove cerco di doppio libero o sovrascrivere l'oggetto dopo che è stato rilasciato.


edit:

Alcuni degli errori che ho ricevuto:

  • FastMM ha rilevato un errore durante l'operazione di scansione blocco libero. FastMM ha rilevato che un blocco è stato modificato dopo essere stato liberato.

  • FastMM ha rilevato un errore durante l'operazione di scansione a blocchi liberi . L'intestazione del blocco è stata danneggiata.

dettaglio:

The current thread ID is 0x19C, and the stack trace (return addresses) leading to this error is: 
402E77 [System][@FreeMem] 
4068DC [System][@DynArrayClear] 
405E2D [System][@FinalizeArray] 
405D31 [System][@FinalizeRecord] 
40432F [System][TObject.CleanupInstance] 
404272 [System][TObject.FreeInstance] 
404641 [System][@ClassDestroy] 
4D313E [UnitSam.pas][TSam.Destroy][297] 
4042BF [System][TObject.Free] 
4149ED [SysUtils][FreeAndNil] 
4D9C0A [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180] 

ho tutte le opzioni "debug" abilitati nella IDE, tra cui il "campo di controllo". Inoltre, FastMM4 è impostato sulla modalità di debug super aggressiva. Senza FastMM o al di fuori del debugger il programma gira bene, ma so che non significa che il bug non sia più lì. In realtà ha funzionato (probabilmente) per più di un anno, fino a quando non ho installato FastMM.


edit:

Grazie a tutti. No, mi sento che mi sto muovendo un po 'nella buona direzione.

La struttura del programma è più complicata. Ho offerto solo il backbone per mantenere il post originale di dimensioni ridotte. Ma che diamine, è già diventato più grande :) Quindi, quegli oggetti TSam sono usati per caricare i dati dal disco. Un file in ogni oggetto. Stanno facendo anche alcuni processi e la convalida dei dati. Per ciascuno di questi TSam ho anche un oggetto grafico che mostra sullo schermo (graficamente) i dati contenuti negli oggetti TSam. Ogni riga in TStringGrid mostra anche i dati in TSam, ma testualmente.

Una domanda che ho: se rompo il programma in pezzi più piccoli per scoprire dove si trova l'errore, l'errore apparirà ancora? O è possibile apparire solo in questa particolare configurazione?


risposta alla domanda "come fa l'AsmJob vengono assegnati a TStringGrid in modo che il TStringGrid distrugge l'AsmJob, ci puoi mostrare?"

MyGrid = TStringGrid 
    public 
    AsmJob: TAsmJob; 
    end; 

poi da qualche parte nel TForm.Create (la forma che contiene la griglia), lo faccio

MyGrid.AsmJob=AsmJob; 

e nel distruttore del MyGrid che faccio:

begin 
    FreeAndNil(AsmJob); 
    inherited 
end; 

risposta

12

Questo errore indica che il codice ha danneggiato le strutture del gestore di memoria interno. Il tuo stack di chiamate rappresenta il punto, quando MM lo ha rilevato. Questo non è un percorso di errore o qualcosa relativo ad esso. L'errore effettivo si verifica PRIMA di questo momento. Può o potrebbe non essere correlato alle citate classi.

You should try to use "Range check errors" option (don't forget to make Build, not Compile) and FastMM in full debug mode (with CheckHeapForCorruption, CatchUseOfFreedInterfaces и DetectMMOperationsAfterUninstall options enabled).

È inoltre possibile attivare la variabile globale FullDebugModeScanMemoryPoolBeforeEveryOperation per ottenere un errore quasi immediatamente dopo il verificarsi di un problema, ma questa opzione rallenta l'esecuzione A LOT.

Probabilmente la scelta migliore è chiamare ScanMemoryPoolForCorruptions periodicamente. Chiamalo in un posto. Hai un errore? Chiamalo prima. Hai ancora un errore? Chiamalo prima di nuovo. Nessun errore? Il tuo problema si trova da qualche parte tra quelle ultime chiamate. Ora puoi utilizzare la variabile FullDebugModeScanMemoryPoolBeforeEveryOperation per ottenere la posizione precisa. Basta accenderlo solo sull'area di questo codice e spegnerlo subito dopo.

C'è un errore molto simile: "FastMM ha rilevato che un blocco è stato modificato dopo essere stato liberato". In questo caso il tuo codice modifica non le strutture interne, ma l'altra memoria, che non è affatto utilizzata ("memoria libera").

BTW, il tuo errore NON è doppio-libero! Se si tratta di una chiamata double-free, FastMM ti dirà esplicitamente (è facile da rilevare, poiché stai provando a liberare blocchi di memoria non utilizzati o non esistenti): "È stato effettuato un tentativo di liberare/riallocare un blocco non allocato ".

+0

Grazie Alessandro. Non avevo idea di "ScanMemoryPoolForCorruptions". Immagino sia una funzione offerta dalla DLL FastMM. Andrò a cercarlo al momento. – Ampere

+0

Questa è la funzione di FastMM4.pas standard. È dalla versione standalone completa di FastMM. Non esiste nella versione di FastMM, che è integrata in Delphi. Non ci sono DLL in questione qui. Questa è solo una funzione nel solito file pas;) – Alex

+0

Purtroppo il link è morto. Ma puoi accedervi al seguente indirizzo: http://web.archive.org/web/20091007162116/http://blog.eurekalog.com/?p=198 – EMBarbosa

4

A l'intestazione del blocco che viene corrotta di solito indica che qualcosa ha sovrascritto la memoria, di solito facendo una sorta di operazione non sicura. Stai usando puntatori grezzi o codice assembly in una delle tue attività? Inoltre, se hai il controllo di intervallo e il controllo dei limiti disattivato, prova ad attivarli e a ricostruirli. Possono aiutare a catturare un sacco di questo tipo di problema.

+0

Ciao massone. No ASM, nessuna operazione di puntatore non elaborata, il controllo di intervallo è SEMPRE acceso. Questo è esattamente quello che sto cercando di capire tutto il giorno oggi: dove potrei sovrascrivere quel maledetto oggetto. – Ampere

+1

Ho visto una situazione simile prima. Alla fine l'ho rintracciato in una libreria di terze parti che stavo usando che stava facendo alcune operazioni con i puntatori grezzi e armeggiando alcuni di essi. Potrebbe essere il caso qui? –

+0

BTW non sembra che non sia l'oggetto che viene sovrascritto, ma l'intestazione del blocco di memoria. Ma, per sicurezza, prova a inserire un punto di interruzione nel codice di pulizia che ti consentirà di esaminare lo stato di questo oggetto prima dell'esecuzione del distruttore. Guardalo nel debugger e assicurati che i suoi campi siano validi. (In caso contrario, è possibile utilizzare un punto di interruzione di indirizzo per trovare la cosa che sovrascrive la memoria banale.) –

1

Un paio di cose e chiedo perché non riesco a vedere il tuo codice.

Dato il seguente codice:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    wObjLst : TObjectList; 
begin 
    wObjLst := TObjectList.Create; 
    try 
     wObjlst.OwnsObjects := true; 
     wObjlst.Add(TPersistent.Create); 
     wObjlst.Add(TPersistent.Create); 
    finally 
     freeandnil(wObjlst); 
    end; 
end; 

Questo funziona con l'errore fuori.

affermate che

At runtime, a form creates a TStringGrid and then the AsmJob which creates those two SAM objects (and load some data from disk in each of them). The AsmJob is also assigned to the grid. When the form is destroyed, the Grid takes care of the AsmJob by freeing it, which frees the TSam objects. Here is the problem: the first object is freed withot problems but the second one dies when its inherited method (in Destroy destructor) is called.

La mia prima domanda è come fa l'AsmJob vengono assegnati a TStringGrid in modo che il TStringGrid distrugge l'AsmJob, ci puoi mostrare?

In secondo luogo, perché creare un discendente di TObjectList per ottenere l'archiviazione di due oggetti e quindi liberarli gratuitamente invece di crearli da soli e lasciare che TObjectList li distrugga come mostrato sopra.

L'altra cosa da provare è scaricare il pacchetto completo di FastMM4 da fastmm.sourceforge.net, installarlo e utilizzare la DLL di fulldebug per individuare esattamente quale oggetto non funziona. Tu ed io pensiamo che sia uno degli oggetti SAM e potrebbe o potrebbe non esserlo.

+0

Ciao Ryan. Originariamente, ObjectList era impostato su OwnObj = true, ma ora ho liberato gli oggetti "manualmente" per vedere dove appare l'errore. Questo è il modo in cui ho indicato che l'errore appare nella chiamata di inherited (destroy) degli oggetti TSam. ANYWAY! Se creo e utilizzo gli oggetti TSam senza manualmente (questo significa senza TAsmJob - che è una sorta di gestore di questi oggetti) tutto funziona semplicemente meraviglioso. Non ho alcun errore. -------- PS: ho già il FastMM in modalità di debug completo. – Ampere

2

Potrebbe esserci una corsa logica da qualche parte nel codice in cui un oggetto viene scritto mentre viene liberato. Aggiungi controlli NULL e altri meccanismi IPC (lock list, ecc.) Per assicurarti che non sia così.

Un'altra opzione potrebbe essere quella di sottoclasse il codice per aggiungere la registrazione ad esso - e controllare se gli oggetti vengono acceduti in modo sequenziale.

Problemi correlati