individuazione del messaggio valgrind "salto condizionato o spostamento dipende da valori non inizializzati"


166

Quindi ho ricevuto qualche misterioso messaggio di valori non inizializzati da Valgrind ed è stato piuttosto il mistero da dove proviene il cattivo valore.

Sembra che valgrind mostri il luogo in cui finisce il valore unitizzato, ma non l'origine del valore non inizializzato.

==11366== Conditional jump or move depends on uninitialised value(s)
==11366==    at 0x43CAE4F: __printf_fp (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43C6563: vfprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x43EAC03: vsnprintf (in /lib/tls/i686/cmov/libc-2.7.so)
==11366==    by 0x42D475B: (within /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E2C9B: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42E31B4: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x42EE56F: std::ostream& std::ostream::_M_insert<double>(double) (in /usr/lib/libstdc++.so.6.0.9)
==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)
==11366==    by 0x810B9F1: Snake::Snake::update() (snake.cpp:257)
==11366==    by 0x81113C1: SnakeApp::updateState() (snakeapp.cpp:224)
==11366==    by 0x8120351: RoenGL::updateState() (roengl.cpp:1180)
==11366==    by 0x81E87D9: Roensachs::update() (rs.cpp:321)

Come si può vedere, diventa piuttosto enigmatico ... specialmente perché quando dice Class :: MethodX, a volte punta direttamente a ostream ecc. Forse questo è dovuto all'ottimizzazione?

==11366==    by 0x81109ED: Snake::SnakeBody::syncBodyPos() (ostream:221)

Proprio così. C'è qualcosa che mi manca? Qual è il modo migliore per catturare valori negativi senza dover ricorrere a un lavoro investigativo di stampa super lungo?

Aggiornare:

Ho scoperto cosa non andava, ma la cosa strana è che valgrind non lo ha segnalato quando è stato usato per la prima volta il valore negativo. È stato utilizzato in una funzione di moltiplicazione:

movespeed = stat.speedfactor * speedfac * currentbendfactor.val;

Dove speedfac era un galleggiante unitizzato. Tuttavia, a quel tempo non è stato segnalato e non fino alla stampa del valore che ottengo l'errore. Esiste un'impostazione per valgrind per modificare questo comportamento?

Risposte:


230

Utilizzare l'opzione valgrind --track-origins=yesper tenere traccia dell'origine di valori non inizializzati. Ciò renderà più lento e occuperà più memoria, ma può essere molto utile se è necessario rintracciare l'origine di un valore non inizializzato.

Aggiornamento: per quanto riguarda il punto in cui viene riportato il valore non inizializzato, il manuale di valgrind afferma :

È importante capire che il tuo programma può copiare i dati spazzatura (non inizializzati) a proprio piacimento. Memcheck osserva questo e tiene traccia dei dati, ma non si lamenta. Un reclamo viene emesso solo quando il programma tenta di utilizzare i dati non inizializzati in un modo che potrebbe influire sul comportamento visibile esternamente del programma.

Dalle FAQ di Valgrind :

Per quanto riguarda la rapida notizia di copie di valori di memoria non inizializzati, questo è stato suggerito più volte. Sfortunatamente, quasi tutti i programmi copiano legittimamente valori di memoria non inizializzati (perché i compilatori si battono per preservare l'allineamento) e il controllo desideroso porta a centinaia di falsi positivi. Pertanto Memcheck non supporta il controllo desideroso in questo momento.


1
Qual è la versione minima di valgrind per utilizzare questa funzione? Sto usando 3.3.0 e non mi piace l'opzione.
Robert S. Barnes,

8
@Robert: --track-origins è stato aggiunto in valgrind 3.4.0
mark4o

20

Ciò significa che si sta tentando di stampare / generare un valore almeno parzialmente non inizializzato. Puoi restringerlo in modo da sapere esattamente quale valore è? Successivamente, traccia attraverso il codice per vedere dove viene inizializzato. È probabile che vedrai che non è stato completamente inizializzato.

Se hai bisogno di ulteriore aiuto, pubblicare le sezioni pertinenti del codice sorgente potrebbe consentire a qualcuno di offrire maggiori indicazioni.

MODIFICARE

Vedo che hai riscontrato il problema. Nota che valgrind osserva il salto condizionato o lo spostamento in base a variabili unitarie. Ciò significa che emetterà un avviso solo se l'esecuzione del programma viene modificata a causa del valore non inizializzato (ad esempio, il programma accetta un ramo diverso in un'istruzione if, ad esempio). Dal momento che l'aritmetica reale non comportava un salto o una mossa condizionale, Valgrind non ti ha avvertito di ciò. Invece, ha propagato lo stato "non inizializzato" al risultato dell'istruzione che lo utilizzava.

Può sembrare controintuitivo che non ti avverta immediatamente, ma come ha sottolineato mark4o , lo fa perché i valori non inizializzati vengono sempre usati in C (esempi: riempimento di strutture, realloc()chiamata, ecc.), Quindi tali avvisi non sarebbero molto utile a causa della falsa frequenza positiva.


Grazie. Ho appena scoperto cosa c'era che non andava, ma la cosa strana è che valgrind non ha riferito la cosa unitaria del valore fino a quando non è stata usata altrove.
Kamziro,

Questo è intenzionale. Se solo la copia o il passaggio di valori non inizializzati causasse un rapporto di errore, li otterresti sempre dal riempimento nelle strutture.
mark4o
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.