Newsgroup: it.comp.lang.c++
Titolo: new, delete

Ho cercato un po' con google groups e poi mi sono rotto...
Nel mio progetto c'č almeno un errore legato all'allocazione di memoria, 
cosě ho pensato di scrivere una classe (da ereditare) per eseguire 
qualche controllo. Voi cosa usate? Esiste qualcosa di freeware e non 
invasivo per risparmiarmi un po' di lavoro?
Kiuhnm

 
Dipende da quali risultati vuoi ottenere.
Ci sono "librerie" piu' o meno complesse e complete per tracciare 
allocazioni/deallocazioni (a volte solo per malloc/free, altre volte 
anche per new/delete).
Un mio collega ha provato "Visual Leak Detector" (licenza LGPL, 
piuttosto specifico per Visual C++), un altro una di cui non ricordo il 
nome.
Se non ricordo male ce ne sono anche per Linux (ehm, ElectricFence?)
Spesso librerie di questo genere danno anche uno stack trace per i 
memory leak ed altre amenita' (data dump dei leak block, bound checking, 
etc...)
Se hai solo bisogno di poche funzionalita' (es. controllare il matching 
tra byte allocati e deallocati) probabilmente non e' difficile fare 
l'overload di new() e delete() (ovviamente la forma meno usata di 
quest'ultimo :-) al livello piu' appropriato (globali o di una classe 
che userai come base per le tue).
-- 
Roal Zanazzi

 che userai come base per le tue).
No, devo avere un problema di buffer overflow da qualche parte perché mi 
fallisce una deallocazione perfettamente "bilanciata".
Proverò VLD e, se non risolvo, ricorrerò al solito metodo 
dell'esclusione binaria :)
Kiuhnm

Kiuhnm ha scritto:

Uhm, allora e' un problema di allocazione di memoria in senso molto 
allargato...
I buffer overflow si possono verificare con un mix di:
- marcatori prima e/o dopo rispetto al blocco di memoria allocato
- breakpoint condizionali su indirizzi di memoria.
- fortuna
- buona sorte
:-)
I buffer overflow "non contigui" (dove non viene sovrascritta la memoria 
dopo il buffer, ma ad indirizzi non prevedibili) sono i piu' pallosi da 
trovare.
-- 
Roal Zanazzi

 trovare.
Non sarà facile trovare l'errore.
Ho perfino allocato blocchi 100 volte più grandi e restituito 
l'indirizzo del punto medio.
Farò come sempre: foglio di carta, matita, gomma, ecc...
Kiuhnm

Kiuhnm ha scritto:

In genere questo errore deriva dalla sovrascrittura dell'indirizzo a cui 
punta la variabile.
Se individui la variabile che dà errore con la delete prova a tenere 
d'occhio il suo indirizzo (dump di memoria) e vedere se e quando cambia 
il contenuto (non il contenuto del buffer). In pratica se l'indirizzo 
ricevuto con la new viene sovrascritto.
Ciao

 ricevuto con la new viene sovrascritto.
E' la prima cosa che ho controllato.
Kiuhnm

Kiuhnm ha scritto:

Ne ero quasi certo :-)
E sicuramente non hai mischiato le chiamate con [] e quelle senza.
Comunque, ti posto qui una funzione che ha avuto un problema, con 
relativo commento (PVect è una mia classe vettore).
Vedi se può rientrare nei tuoi casi.
<code>
//----------------------------------------------------------------------
// da usarsi solo in caso di vettore di puntatori
//----------------------------------------------------------------------
template <class T>
void flushPV(PVect<T>& v)
{
   int nElem = v.getElem();
   for(int i = 0; i < nElem; ++i) {
     // Il compilatore ha generato codice errato quando la routine veniva
     // richiamata in un distruttore inline (in pratica richiamava 
delete (void*)).
     // Forzando una variabile locale sul tipo di dato sembra che 
richiami il
     // distruttore giusto per gli oggetti allocati
#if 0
     delete v[i];
#else
     T tmp = v[i];
     delete tmp;
#endif
     }
   v.reset();
}
</code>

 
In genere con i breakpoint condizionali sulla memoria me la sono cavata
quasi sempre, ma è innegabile che ci vogliano anche una buona dose di
fortuna e possibilmente anche vari talismani anti-malocchio. Se è un
progetto grande può volerci del tempo, ma prima o poi è inevitabile
incappare nell'errore.
I marcatori davanti ai blocchi di memoria tendo ad evitarli perché se ti
capita di avere delle librerie esterne che (de)allocano qualcosa per
conto tuo è abbastanza problematico.
Tanto per la cronaca (e magari è quello che ti succede!) una volta
Visual Studio 2005 mi allocava con la new meno bytes di quelli necessari
a contenere una classe e pertanto mi diceva sempre che c'era un overrun
al momento della delete. Dopo una settimana di disperazione ho risolto
aggiungendo un "virtual" davanti a una funzione derivata che faceva
l'override di una funzione virtual del padre. È tuttora un mistero
comunque per me, dato che la parola chiave virtual è opzionale se non
vado errato... o no? Fai una sizeof() della classe e vedi se corrisponde
alle dimensioni reali compresa la vtable se è virtuale.
Andrea.

 Vedi se puň rientrare nei tuoi casi.
No, non č il mio caso, ma ho appena trovato l'errore!
E' oltremodo stupido! :(((
Ho aggiunto un distruttore statico a una classe e ho dimenticato il 
distruttore normale.
Nel distruttore statico distruggo le strutture interne e, quando chiamo 
delete sull'intera struttura, viene chiamato il distruttore che prova a 
ridistruggere le stesse strutture!
Ho corretto aggiungendo un cast a (void *).
Magari dovrei aggiungerci un piccolo commento...
static void destroy(Segment<T>* s)
{
	s->uninit();
	delete (void *)s;
}
Kiuhnm

 }
Oggi non connetto...
Basta
static void destroy(Segment<T>* s)
{
     delete s;
}
Kiuhnm

Kiuhnm ha scritto:

:-)
mi sembrava un po' strana la prima versione. Rischi di avere lo stesso 
mio problema in quanto non puoi sapere in che modo (da quale zona di 
memoria) č stato allocato il puntatore. Sicuramente la seconda č piů 
pulita :-)
Ciao


Stavo giusto domandandomi quale poteva essere lo scopo di questa sorta
di two phase finalization...
Ciao,
Nicola

 di two phase finalization...
Sul momento, anziché eliminare s->uninit(), ho aggiunto (void *).
Kiuhnm