View Full Version : Errore in Cpp - come lo scovo???
Salve,
sto sviluppando un programma in c++, ma da ieri mi sono bloccato alla ricerca di un errore che non riesco a scovare. Il programma ha uno stream di output su un file all'interno del quale vengono appesi dei risultati ottenuti durante la computazione. Fino a ieri tutto andava bene, poi sono iniziati i problemi; è altamente probabile che si tratti di un errore di memoria:
- Come si manifesta l'errore:
Lancio il programma, quando è terminato, apro il file in cui vengono scritti i risultati e si vede che la parte iniziale dei dati è stata cancellata e sostituita da quadratini vuoti (sotto linux), sotto windows appaiono come quadrati pieni se apro il file con textpad o come spazi bianchi se lo apro con blocco note.
- Quando si manifesta l'errore:
Si manifesta in modo molto strano. Supponiamo che il programma mi funzioni. Prendo una funzione di una classe, in cui c'è un costrutto switch, aggiungo un ramo case fittizio in cui non faccio nulla:
case(50){
break;
}
durante l'esecuzione il valore 50 nn è mai quello passato nello switch. Questo basta per corrompere il file.
Oppure, in un altra funzione dichiaro delle variabili stringa:
std::string a1("aaaaaaaa");
std::string a2("aaaaaaaa");
std::string a3("aaaaaaaa");
std::string a4("aaaaaaaa");
std::string a5("aaaaaaaa");
variabili che non sono utilizzate in alcun modo, ne ci sono altre variabili o campi con lo stesso nome da qualke altra parte; questo basta a corrompere il file.
Oppure in un altra funzione di un altra classe dichiaro un ofstream:
std::ofstream t1("a.a");
tutto ok
se ne dichiaro 2
std::ofstream t1("a.a");
std::ofstream t1("b.b");
file corrotto, anche se i files a.a e b.b non vengono in alcun modo coinvolti nel programma, sono semplicemente delle dichiarazioni che restano inutilizzate.
E altri esempi simili; insomma sembra che basti aggiungere istruzioni apparentemente innocue, e che al limite neanche vengono eseguite, come il ramo case fittizio, che si presenta il problema.
Ora, quello che vorrei sapere da voi è se sapete suggerirmi dei procedimenti o strumenti per effettuare il debug, visto che non ho mai usato strumenti appositi per il debug, e non so come procedere. Purtroppo non posso postare il codice perke è costituito da molte classi e fa uso anche di una libreria installata sul mio sistema. Il tutto avviene sotto linux. Mi piacerebbe avere suggerimenti per sapere come monitorare il file che viene corrotto, perke quando c'è un bug su una variabile si puo risolvere semplicemente, stampando qua e la la variabile per vederne il valore, qui non so come fare per vedere quand'è che subentra l'errore nello stream e soprattutto qual è l'errore che va a sovrascrivere qualke dato in memoria provocando l'errore, perkè è ovvio che gli esempi che ho descritto sopra non sono la causa dell'errore, ma sono solo esempio che rendono visibile l'errore.
Ogni suggeriemnto è benacceto, grazie e ciao. :mc:
end.is.forever
26-10-2004, 12:13
Sei sicuro di aver chiuso il file dopo le scritture?
ilsensine
26-10-2004, 12:19
Benvenuto nel meraviglioso mondo dei buffer overflow. Potrebbe anche essere un doppio free/doppio delete/puntatore non inizializzato.
Non una bella cosa da debuggare, soprattutto se il programma non è strutturato in maniera molto pulita.
Tutti gli stream usati non sono creati dinamicamente, ma sono campi di una classe, questo vale anche per lo stream principale, per cui il distruttore dovrebbe chiuderlo automaticamente, ma anche chiudendolo esplicitametne la situazione nn cambia. ilsensine, lo so che è un errore di memoria, il fatto è che in tutto il programma uso new solo in un punto per creare un oggetto che passo al costruttore di una classe della libreria che uso, e che si assume l'ownership su quell'oggetto, e provvede a distruggerlo alla fine. Nn ho fatto nessun altro new o delete nei miei files. E' improbabilme che possiate indicarmi l'errore senza vedere il programma, vorrei solo sapere come posso procedere per il debug. :muro:
ilsensine
26-10-2004, 12:43
Originariamente inviato da anx721
Tutti gli stream usati non sono creati dinamicamente, ma sono campi di una classe, questo vale anche per lo stream principale, per cui il distruttore dovrebbe chiuderlo automaticamente, ma anche chiudendolo esplicitametne la situazione nn cambia. ilsensine, lo so che è un errore di memoria, il fatto è che in tutto il programma uso new solo in un punto per creare un oggetto che passo al costruttore di una classe della libreria che uso, e che si assume l'ownership su quell'oggetto, e provvede a distruggerlo alla fine. Nn ho fatto nessun altro new o delete nei miei files. E' improbabilme che possiate indicarmi l'errore senza vedere il programma, vorrei solo sapere come posso procedere per il debug. :muro:
Quindi resterebbe l'ipotesi del buffer overflow...
Occorrerebbe vedere una bozza di codice compilabile per riprodurre il problema.
Originariamente inviato da ilsensine
Quindi resterebbe l'ipotesi del buffer overflow...
Occorrerebbe vedere una bozza di codice compilabile per riprodurre il problema.
Purtroppo faccio uso di una libreria (CppUnit) che ho instalalto, per cui i miei files non posso passarli perke non sarebbero compilabili. Piu tardi vedo se usando solo la classe che si occupa di gestire gli stream e che è indipendente dalle altre ho ancora il problema, se cosi fose potrei passarvela, ma a quel punto sarebbe anche piu facile per me trovare l'errore perche sarebbe tutto piu circoscritto. Non vorrei che l'errore sia causato dalla libreria che sto usando, perke in tal caso la cosa sarebbe piu difficile da sistemare, anche se la libreria è fornita con codice sorgente e potrei ricompilarla.
Resto in attesa di suggerimenti su come procedere per il debug, gdb (che non ho mai usato), mi puo essere utile? grazie e ciao.
ilsensine
26-10-2004, 13:09
Senza impazzire con gdb, puoi usare kdevelop, che ha una ottima interfaccia con gdb. Puoi eseguire il programma passo-passo, cercando l'overflow.
Ti consiglio di compilare la libreria con le opzioni di debug, in modo da poterla seguire nel trace del codice.
Ho installato valgrind per il debug:
http://valgrind.kde.org/
e ho provato a laciare il programma in questa macchina virtuale che controlla tutte le scritture/letture in memoria, ma non mi rileva alcun errore...le mie classi sono state compilate con l'opzione -g (è giusta per il debug?)
Comuqnue non ho ricompilato la libreria con l'opzione di debug, ma l'ho usata cosi com'è.
Ho anche messo kdevelop; ora per usare gdb dovrei mettere dei break point nel programma e farlo eseguire passo passo controllando il contenuto del file durante il debugging? Che altro potrei fare?
Grazie e ciao.
Originariamente inviato da ilsensine
Puoi eseguire il programma passo-passo, cercando l'overflow.
Ma cosa dovrei fare di preciso? Come faccio a cercare l'overflow??? Ammesso che ci sia una qualke istruzione che va a scrivere in memoria alterando il contenuto di certe variabili, come faccio ad individuare ciò? Dovrei avere un'immagine di tutta la memoria utilizzata dal mio programma e controllarla tutta per ogni singola istruzione eseguita...ma come posso realizzare una cosa del genere?
Qualcuno puo avere qualke idea poi del perke l'errore non dà mai segmentation fault, ma si manifesta sempre alterando il contenuto del file; in particolare avviene che dino ad un certo punto il file è ok, si esegue un'istruzione che appende del testo al file e come effetto si ottiene che il testo viene appeso alla fine, ma allo stesso tempo una porzione del testo iniziale viene sostituita da quadratini...help.... :cry: :cry: :cry:
Grazie e ciao
ilsensine
27-10-2004, 14:47
Originariamente inviato da anx721
Ma cosa dovrei fare di preciso?
Difficile a dirsi per chi non ha fatto quel programma...
Per isolare il problema, innanzitutto comincia a "togliere pezzi" al programma, in modo da debuggarlo con più semplicità. Senza codice sorgente non è facile aiutarti (e anche se lo puoi distribuire, immagino che non si tratti proprio di "un paio di righe di codice"...)
Altro suggerimento che ti do: ricompila il programma (e la libreria che usa!) senza _nessuna_ ottimizzazione, e verifica se produce gli stessi errori.
Originariamente inviato da ilsensine
Per isolare il problema, innanzitutto comincia a "togliere pezzi" al programma
Il fatto è che se inizio a togliere pezzi il problema scompare, ma non dipende dal pezzo, cioè se tolgo un pezzo non si ha il problema, se rimetto quel pezzo e ne tolgo un altro non si aha il problema, oppure se aggiungo dell'altro codice nn si ha il problema, insomma tutto dipende penso dalla configurazione della memoria nel momento in cui si lancia il programma, e comuqnue non posso togliere molto perchè tutte le classi sono fortemente collegate tra di loro. Mi è pure capitato che due esecuzioni dello stesso proramma dessero una volta l'errore e una volta no...
Altro suggerimento che ti do: ricompila il programma (e la libreria che usa!) senza _nessuna_ ottimizzazione, e verifica se produce gli stessi errori.
Se l'errore scomparisse non poteri pero sapere se dipendeva dalle ottimizzazioni o semplicemente l'errore c'è ancora, solo che non è visibile. come ho gia fatto notare basta aggiungere un 'istruzione che non fa niente per avere l'errore.
Comuqnue vedo se posso ricompilare o magari aggiungere direttamente i file sorgenti della libreria al mio progetto e linkarla staticamente al mio programma.
Grazie e ciao.
Aggiornamento:
ho ricompilato la libreria come indicato da ilsensine, senza ottimizzazione, ma l'errore si manifesta ancora.
Ho fatto altre 2 prove:
1 - inserendo i files della libreria nel mio progetto;
2 - ho portato tutto il progetto su windows, nella versione che comprende i files della libreria.
Ho poi creato due versioni del codice codice1, codice2. Questo è quello che accade:
Dinamca = libreira installata e caricata dinamicamente
Statica = libreria compilata col mio programma
StaticaWin = libreria compilata nel mio programma, sotto windows
--------------- Dinamca -------- Statica ------- StaticaWin
codice1 Errore OK OK
codice2 Errore Errore OK
In pratica con la libreria instalalta nel sistema si ha errore in entrambi i casi, con la libreria nel mio programm si ha l'errore solo nel secondo caso (in cui le funzioni che scrivono nel file vengono chiamate piu volte); sotto windows l'errore non si manifesta in nessuno dei due casi. In tutti e 3 i casi di errore sotto linux i primi 141 caratteri vengono sostuiti ciascuno da un quadratino, uno per ogni carattere.
Come al solito dò queste informazioni non perche spero che qulkuno mi dica dove sbaglio, ma perche magari chi è piu esperto di me puo avere dei suggerimenti da fare, o capire che tipo di errore ci sia o suggerire altre prove.
Grazie e ciao.
ilsensine
28-10-2004, 08:07
Il fatto che senza ottimizzazioni riproduci lo stesso errore, sembrerebbe escludere una gestione scorretta della memoria. Inoltre, se anche su win riesci, in determinati casi, a riprodurre lo stesso errore, rafforza questa idea.
Sono un pò confuso, sinceramente. Ammesso anche che si tratti di un bug nella libreria, non si capisce perché con la versione statica funziona (sotto linux), ma con quella dinamica no...
Almeno ora hai delle versioni che sembrano funzionare...
Su win non sono ancora riuscito a riprodurre l'errore, nonostante utilizzi gli stessi sorgenti che uso sotto linux con il compilatore mingw, ma farò altre prove.
Sotto linux l'errore si presenta sia con la versione statica che con quella dinamica, anche se ho fatto un esempio in cui si presenta solo con la dinamica :confused:
D'altro canto il fatto che lo stesso sorgente funziona sotto win ma non sotto linux non dovrebbe escludere un errore funzionale del programma?
Ho fatto un'altra prova (che forse avrei dovuto fare dall'inizio); finora ho lavorato con linux installato in una macchina virtuale (VMWare), cosi avevo windows attivo, e dentro vmware avevo linux (madrake 10). Comuqnue, ho provato ad eseguire il programma direttamente da linux e non ho il problema nè nella versione linkata dinamicamente con la libreria, nè con quella statica. Sotto vmware eseguivo il programma su una partizione fat32 montata nel filesystem: questo probabilmente è il problema, perchè dopo le prove positive ottenute eseguendo direttamnte sotto linux, ho provato ad eseguire il programma sempre dentro vmware ma non nella partizione fat32, e là ha funzionato.
Spero che il problema sia effettivametne questo; ho anche eseguito il debug passo passo impostando nell'ofstream come buffer un mio array di caratteri, in modo da poterne controllare il contenuto durante tutta l'esecuzione, e il contenuto era sempre esatto, ma quando eseguivo il flush comparivano i quadratini.
Mi piacerebbe tuttavia avere qualke altra conferma del funzionamento del programma. per questo l'ho messo in rete a questo indirizzo:
http://xoomer.virgilio.it/world721/tests/tests.zip
Se qualcuno vuole fare una prova, basta scompattare ed eseguire il file tests
./tests
sarà creato un file tests.txt che, se tutto è andato bene, dovra essere uguale a tests_corretto.txt; se invece vi trovate caratteri strani o le prime righe mancanti significa che qlkosa nn va.
Grazie (soprattutto al sensine), e ciao.
ilsensine
30-10-2004, 20:25
Originariamente inviato da anx721
Ho fatto un'altra prova (che forse avrei dovuto fare dall'inizio); finora ho lavorato con linux installato in una macchina virtuale (VMWare), cosi avevo windows attivo, e dentro vmware avevo linux (madrake 10). Comuqnue, ho provato ad eseguire il programma direttamente da linux e non ho il problema nè nella versione linkata dinamicamente con la libreria, nè con quella statica. Sotto vmware eseguivo il programma su una partizione fat32 montata nel filesystem: questo probabilmente è il problema, perchè dopo le prove positive ottenute eseguendo direttamnte sotto linux, ho provato ad eseguire il programma sempre dentro vmware ma non nella partizione fat32, e là ha funzionato.
Più che strano. Direi "inquietante".
Domanda/dubbio: la partizione "fat32" montata da linux dentro vmware, era anche montata/utilizzata dal windows reale?
Se la risposta è "sì", fai uno scandisk accendendo qualche cero. Hai sicuramente corrotto qualcosa nel file system.
La partizione era montata dentro windows (xp). Comuqnue ho eseguito lo scandisk di windows e non mi rileva errori, neanche il comando chkdsk eseguito dentro l'unita mi rileva nulla. Se avvio linux che ho instalato sempre nel mio pc, quindi non dentro vmware, se eseguo il programma sempre in quella partizione non ho il problema. ilsensine, hai provato per caso ad eseguire il mio programma e controllato che non ti dia errori?
Grazie e ciao.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.