PDA

View Full Version : [c++] Tool per errori con la memoria


Sabonis
12-07-2008, 12:51
Mi sapete consigliare qualche buon tool per scoprire errori di memoria come memory leak, buffer overflow etc?
Valgrind è molto buono ma non trova errori di questo tipo:

int static[5];

int main(void)
{
int stack[5];

static[5] = 0;
stack [5] = 0;

return 0;
}

Esiste qualche tool che possa trovare errori di questo genere?

VICIUS
12-07-2008, 14:11
Non vedo errori nel codice tranne l'uso di una parola chiave come nome di variabile ma per questo basta un qualsiasi compilatore.

marko.fatto
12-07-2008, 14:21
Non vedo errori nel codice tranne l'uso di una parola chiave come nome di variabile ma per questo basta un qualsiasi compilatore.

forse che il quinto elemento è in posizione 4 mentre quello a cui cerca di accedere sarebbe il sesto elemento? :Prrr:

Unrue
12-07-2008, 14:42
Mi sapete consigliare qualche buon tool per scoprire errori di memoria come memory leak, buffer overflow etc?
Valgrind è molto buono ma non trova errori di questo tipo:

int static[5];

int main(void)
{
int stack[5];

static[5] = 0;
stack [5] = 0;

return 0;
}

Esiste qualche tool che possa trovare errori di questo genere?

Si, esiste. E' una particolare versione di gcc, chiamato bounds-checking. E' una patch da applicare. Funziona molto bene, rileva sforamenti sia nello stack che nell'heap.

Dopo che hai scaricato la patch:
http://sourceforge.net/project/showfiles.php?group_id=88372

Compila con -fbounds-checking. L'unica cosa è che non so se funziona anche con C++. ma tanto il codice che hai scritto è C :)

VICIUS
12-07-2008, 14:44
forse che il quinto elemento è in posizione 4 mentre quello a cui cerca di accedere sarebbe il sesto elemento? :Prrr:
Cavolo hai ragione. Sono troppo abituato a ruby/c# :p

71104
12-07-2008, 15:07
Cavolo hai ragione. Sono troppo abituato a ruby/c# :p
:wtf: non mi risulta che in C# gli indici degli array partano da 1

Sabonis
12-07-2008, 15:18
Si, esiste. E' una particolare versione di gcc, chiamato bounds-checking. E' una patch da applicare. Funziona molto bene, rileva sforamenti sia nello stack che nell'heap.

Dopo che hai scaricato la patch:
http://sourceforge.net/project/showfiles.php?group_id=88372

Compila con -fbounds-checking. L'unica cosa è che non so se funziona anche con C++. ma tanto il codice che hai scritto è C :)

Mi servirebbe un tool per il c++!

Unrue
12-07-2008, 15:32
Mi servirebbe un tool per il c++!

Mi pare che si possa applicare anche a g++. :) Prova

E comunque, se programmi in C++, la cosa migliore è usare i vector, che con il metodo at() controllano gli indici nativamente.

DanieleC88
12-07-2008, 16:28
Non vedo errori nel codice tranne l'uso di una parola chiave come nome di variabile ma per questo basta un qualsiasi compilatore.
Questa è l'età... :O :Prrr:

Quel codice, se fosse un film, si chiamerebbe...
Il Quinto Elemento!




ok, scappo da solo... :ops:

71104
12-07-2008, 16:37
E comunque, se programmi in C++, la cosa migliore è usare i vector, che con il metodo at() controllano gli indici nativamente. mah, non credo che valga la pena di usare i vector per un problema del genere; i vantaggi di vector sono altri, ma se si tratta di usare un array di dimensioni note e fisse usare vector non è certo meglio che usare qualche sistema per il controllo degli errori di memoria.

71104
12-07-2008, 16:37
Questa è l'età... :O :Prrr:

Quel codice, se fosse un film, si chiamerebbe...
Il Quinto Elemento!




ok, scappo da solo... :ops:

asdasdasdasdasdasdasdasdasd

Unrue
12-07-2008, 21:07
mah, non credo che valga la pena di usare i vector per un problema del genere; i vantaggi di vector sono altri, ma se si tratta di usare un array di dimensioni note e fisse usare vector non è certo meglio che usare qualche sistema per il controllo degli errori di memoria.

In C++ non credo esista altro per controllare gli indici. Quindi mi pare l'unica soluzione praticabile.

Neanche Valgrind prende quegli errori purtroppo. E poi non è detto che lui debba lavorare solo con array a dimensioni fisse :)

Un'alternativa più spinta è compilare ll codice da controllare con il gcc patchato con bounds checking e tutto il resto passarlo al compilatore c++. Però non l'ho mai fatto e sinceramente non so neanche se sia fattibile.

71104
13-07-2008, 12:44
In C++ non credo esista altro per controllare gli indici. Quindi mi pare l'unica soluzione praticabile. si può anche scrivere un piccolo template ad hoc, che risulterebbe meglio di vector perché quest'ultima ha un problema: il bound checking lo fa sempre, ma nella build di release è inutile. tra l'altro ribadisco che secondo me è inutile scomodare vector se le dimensioni dell'array sono fisse.

questo è un template che ho scritto or ora e che potrebbe rimpiazzare gli array normali:

template<typename _Type, int _Size>
class CheckedArray
{
private:
_Type Data[_Size];

public:
inline _Type &operator [] (unsigned int Index)
{
assert(Index < _Size);
return Data[_Size];
}

};


non ci vuole niente a scriverlo e risolve il problema meglio di vector.

Unrue
13-07-2008, 20:53
si può anche scrivere un piccolo template ad hoc, che risulterebbe meglio di vector perché quest'ultima ha un problema: il bound checking lo fa sempre, ma nella build di release è inutile.


Non è vero. Il bound checking il vector lo fa solo se accedi con questa sintassi all'elemento i:

vettore.at(i);

Dunque con il metodo at(). Se ci accedi direttamente:

vettore(i);

Non fa alcun controllo. Dunque in fase di debug usi at(). In release, togli il metodo e ci accedi direttamente.


questo è un template che ho scritto or ora e che potrebbe rimpiazzare gli array normali:

template<typename _Type, int _Size>
class CheckedArray
{
private:
_Type Data[_Size];

public:
inline _Type &operator [] (unsigned int Index)
{
assert(Index < _Size);
return Data[_Size];
}

};


non ci vuole niente a scriverlo e risolve il problema meglio di vector.

Beh, a mano puoi fare tutto. Lui chiedeva se c'era un tool che già lo fa. Dunque, a parte il gcc patchato (che non sono sicuro che vada con C++) ed i vector, non c'è nulla :)

71104
13-07-2008, 22:11
Non è vero. Il bound checking il vector lo fa solo se accedi con questa sintassi all'elemento i:

vettore.at(i);

Dunque con il metodo at(). Se ci accedi direttamente:

vettore(i);

Non fa alcun controllo. Dunque in fase di debug usi at(). In release, togli il metodo e ci accedi direttamente. su che hai capito benissimo: a parte che l'operatore per l'accesso diretto sono le parentesi quadre, non le tonde, ma a parte quello il metodo at il bound checking lo fa sempre, sia in modalità di debug che di release; e riempire il codice di #ifdef _DEBUG ad ogni singolo accesso al vettore mi sembra eccessivo, così i tempi di scrittura si quintuplicano :sofico:



Beh, a mano puoi fare tutto. no, a mano non puoi fare tutto: se una cosa non è ragionevole farla non la fai. ma se ti preme il bound checking questa soluzione mi sembra ragionevolissima per quanto poco tempo e quante poche modifiche al codice esistente richiede.

Unrue
14-07-2008, 14:24
su che hai capito benissimo: a parte che l'operatore per l'accesso diretto sono le parentesi quadre, non le tonde,


Ah beh, errore colossale..:rolleyes: Non c'è bisogno di rispondere con ironia a fronte di sviste..


ma a parte quello il metodo at il bound checking lo fa sempre, sia in modalità di debug che di release; e riempire il codice di #ifdef _DEBUG ad ogni singolo accesso al vettore mi sembra eccessivo, così i tempi di scrittura si quintuplicano :sofico:

Non mi hai capito: io ho detto che il bound checking il vector lo fa con il metodo at, se ci accedi direttamente no. MI pareva di aver scritto chiaro..:stordita:

Nessun ifdef nel codice. In debug usi il metodo at, in release lo togli. Quante milioni di volte lo userai mai nel codice..

71104
14-07-2008, 20:54
Ah beh, errore colossale..:rolleyes: Non c'è bisogno di rispondere con ironia a fronte di sviste.. anima candida, quella la chiami ironia? :asd:

ecco, questa è ironia :sofico:


Nessun ifdef nel codice. In debug usi il metodo at, in release lo togli. appunto... l'ifdef serve a vedere se sei in debug o in release:

#ifdef _DEBUG
... vettore.at(i) ...
#else
... vettore[i] ...
#endif



Quante milioni di volte lo userai mai nel codice.. e che ne sai, può essere un programma che fa un uso intensivo degli array, tantopiù se gli preme il bound checking.

sottovento
15-07-2008, 08:36
Mi sapete consigliare qualche buon tool per scoprire errori di memoria come memory leak, buffer overflow etc?
Valgrind è molto buono ma non trova errori di questo tipo:

int static[5];

int main(void)
{
int stack[5];

static[5] = 0;
stack [5] = 0;

return 0;
}

Esiste qualche tool che possa trovare errori di questo genere?

La piattaforma e' Windows? In tal caso, hai a disposizione diverse tecniche per riuscire a trovare errori di questo tipo, specialmente se usi Visual...

Sabonis
15-07-2008, 09:19
La piattaforma e' Windows? In tal caso, hai a disposizione diverse tecniche per riuscire a trovare errori di questo tipo, specialmente se usi Visual...

Si va bene sia per windows che per linux che per mac

marco.r
15-07-2008, 11:10
si può anche scrivere un piccolo template ad hoc, che risulterebbe meglio di vector perché quest'ultima ha un problema: il bound checking lo fa sempre, ma nella build di release è inutile.

Eventuali bug spariscono automaticamente ? :mbe: :D

marco.r
15-07-2008, 11:16
e che ne sai, può essere un programma che fa un uso intensivo degli array, tantopiù se gli preme il bound checking.
Tipicamente faranno parte di una qualche classe che li wrappa opportunamente, e che fa i controlli quando serve, ma non di piu'. In quel modo li posso lasciare pure in release.
Ad esempio se usi matrici la maggior parte delle operazioni costose non le fai elemento per elemento, ma sulla matrice intera, una parte della stessa (colonna, riga, etc.)

71104
15-07-2008, 12:45
Eventuali bug spariscono automaticamente ? :mbe: :D si suppone che tu li abbia rimossi tutti nella build di debug. per quelli che sono rimasti comunque non ci puoi fare nulla: l'utente non è in grado di caricare un dump in un debugger o di analizzare vagonate di numeri esadecimali, quindi lascia che il tutto crashi e che venga richiesto all'utente di inviare al team i dati per il debug. è il concetto della macro assert (infatti nel mio template ho usato proprio quella).

marco.r
15-07-2008, 13:28
si suppone che tu li abbia rimossi tutti nella build di debug. per quelli che sono rimasti comunque non ci puoi fare nulla: l'utente non è in grado di caricare un dump in un debugger o di analizzare vagonate di numeri esadecimali, quindi lascia che il tutto crashi e che venga richiesto all'utente di inviare al team i dati per il debug. è il concetto della macro assert (infatti nel mio template ho usato proprio quella).
E' un rischio, soprattutto se il progetto e' abbastanza grosso. Preferisco un programma che si pianta e perdo il lavoro a uno che senza dirmi niente mi corrompe i dati.
Anche perche', nella mia esperiena si possono tenere i controlli senza inficiare in modo percettibile le prestazioni.

DanieleC88
15-07-2008, 15:24
Non era quello che intendeva 71104: una volta che tu hai completato il debugging, se resta qualche problema che può causare il crash del software, all'utente finale che riceve la versione release non può fregare di meno di sapere dove questo succeda, non saprebbe cosa farsene di quelle informazioni.

VICIUS
15-07-2008, 16:27
Come dice marco.r perché togliere le assert? Se una fallisce vuol dire che c'è un errore grave e il programma deve fermarsi immediatamente. Se si continua c'è il rischio di corrompere i dati o peggio ancora di ricevere risultati errati senza che nessuno se ne accorga e questo è infinitamente peggio di un blocco.

Il programma finito è esattamente dove servono realmente le assert. All'utente finale potrà anche non interessare che nel file A alla riga 12 l'espressione x > 0 non è verificata ma qualcosa capisce lo stesso, intuisce che è importante e forse te lo aggiunge alla mail di protesta insieme con il classico "Il programma non funziona".

71104
15-07-2008, 17:19
il punto chiave della questione è che alcuni bug tra quelli di index out of bound causano un crash, altri corrompono silenziosamente i dati. assert è fatta per dare una soluzione solamente al primo tipo di bug, per quelli del secondo tipo invece non c'è soluzione se non quella di un testing molto approfondito in fase di debug, possibilmente esaustivo. dal momento che difficilmente un testing esaustivo è possibile, e dal momento che la assert funziona così by design (vedere su www.cplusplus.com), è necessario definire una propria versione di assert leggermente modificata che nella build di release causi un crash. esempio per Win32:

#ifdef _DEBUG
#define myassert assert
#else
#define myassert 1 ? DebugBreak() :
#endif


a quel punto si sostituisce assert con myassert nel codice del template che avevo scritto e la soluzione va ancora benissimo.

banryu79
15-07-2008, 17:40
Interessante, non avendo mai programmato seriamente in C++ non conoscevo questa tecnica.
Geniale l'assert personalizzata: è certo meglio crashare di brutto che sputtanare dati in "modalità stealth".

Ma è l'unico metodo pratico/sicuro per pararsi il culo per la realese version o esistono delle alternative?

71104
15-07-2008, 17:54
in realtà ho scritto una boiata :sofico:
la mia versione personalizzata in release non fa altro che crashare sempre :asd:

la corrego :D

#ifdef _DEBUG
#define myassert assert
#else
#define myassert(x) ((x) ? true : (DebugBreak(), false))
#endif

DanieleC88
15-07-2008, 18:08
la corrego :D
Che fai tu? La corregi? :p

In effetti prima me ne sfuggiva il funzionamento... :D

cavay
15-07-2008, 21:44
Mi sapete consigliare qualche buon tool per scoprire errori di memoria come memory leak, buffer overflow etc?
Valgrind è molto buono ma .....
Esiste qualche tool che possa trovare errori di questo genere?

Io utilizzo dei prodotti della parasoft e mi trovo benissimo...quello che farebbe al caso tuo è http://www.parasoft.com/jsp/products/home.jsp?product=Insure

ovviamente non è open-source ne free..

salvodel
16-07-2008, 11:05
Si, esiste. E' una particolare versione di gcc, chiamato bounds-checking. E' una patch da applicare. Funziona molto bene, rileva sforamenti sia nello stack che nell'heap.

Dopo che hai scaricato la patch:
http://sourceforge.net/project/showfiles.php?group_id=88372

Compila con -fbounds-checking. L'unica cosa è che non so se funziona anche con C++. ma tanto il codice che hai scritto è C :)

Scusate se mi intrometto ma volevo sapere una cosa, anzi due:

come si applica la patch?
quale versione devo scegliere? In Synaptic risultano installate le versioni di gcc 3.3/3.4 e 4.1/4.2

Grazie.

Unrue
16-07-2008, 16:57
Scusate se mi intrometto ma volevo sapere una cosa, anzi due:

come si applica la patch?
quale versione devo scegliere? In Synaptic risultano installate le versioni di gcc 3.3/3.4 e 4.1/4.2

Grazie.

La versione più aggiornata su cui puoi applicarla è la 4.0.2. Il comando da usare per applicarla è scritto nella patch stessa. Ovviamente poi devi ricompilare il gcc.

salvodel
16-07-2008, 17:42
La versione più aggiornata su cui puoi applicarla è la 4.0.2. Il comando da usare per applicarla è scritto nella patch stessa. Ovviamente poi devi ricompilare il gcc.

Mi sa che sono troppo 'gnurant :bsod: per utilizzarlo, non so come ricompilare gcc...continuo a fare ad occhio mi sa :coffee:.
Grazie

Unrue
16-07-2008, 22:34
Mi sa che sono troppo 'gnurant :bsod: per utilizzarlo, non so come ricompilare gcc...continuo a fare ad occhio mi sa :coffee:.
Grazie

Non puoi farlo con Synaptic. Devi scaricarti i sorgenti, patcharlo, far girare il configure e compilarlo con il make. ;)