Ho notato un comportamento molto strano di snprintf con C++ su diverse piattaforme. Si consideri il seguente codice (ad esempio minimo di lavoro che fa sì che il comportamento osservato):Comportamento snprintf imprevisto
#include <stdio.h>
char test1[512];
char test2[512];
char test3[1024];
char test4[1024];
int main()
{
snprintf(test1, sizeof(test1), "test1");
snprintf(test2, sizeof(test2), "test2");
snprintf(test3, sizeof(test3), "%s %s", test1, test2);
return 0;
}
Quando in esecuzione anche se valgrind con --tool = exp-sgcheck, viene segnalato il seguente errore (per l'istruzione 3 ° snprintf):
==30302== Invalid read of size 1
==30302== at 0x568E4EB: vfprintf (in /lib64/libc-2.19.so)
==30302== by 0x56B7608: vsnprintf (in /lib64/libc-2.19.so)
==30302== by 0x5695209: snprintf (in /lib64/libc-2.19.so)
==30302== by 0x4006AD: main (1.cc:12)
==30302== Address 0x601460 expected vs actual:
==30302== Expected: global array "test1" of size 1,024 in object with soname "NONE"
==30302== Actual: global array "test2" of size 512 in object with soname "NONE"
==30302== Actual: is 0 after Expected
Quindi passare test1 come argomento al primo% s porta a una lettura dopo la fine dell'array test1.
Questo comportamento ha causato diversi errori di pagina in un driver di Windows (sì, so che sono dati statici ...). Fortunatamente il codice è portatile e quando è stato portato su Linux valgrind ha segnalato questo errore.
Ma per quanto ne so, snprintf dovrebbe terminare test1 con \ 0 al sesto byte (che fa, controllato che). Quindi, perché la terza istruzione snprintf viene letta dopo la fine dell'array test1? Modifica della dichiarazione 3 ° snprintf a
snprintf(test3, sizeof(test3), "%.512s %s", test1, test2);
risolve il problema su entrambe le piattaforme. La compilazione del codice come codice C (non C++) non genera errori.
UPDATE: Su linux (e forse anche Windows) l'errore si verifica solo se il codice è compilato con le informazioni di debug incluse e le ottimizzazioni disabilitate (-g -O0 per gcc).
Non che in questo caso dovrebbe fare la differenza, ma il nome del file sorgente viene chiamato nell'output di valgrind come '1.cc'. C'è qualche ragione per scrivere C e compilarlo con un compilatore C++? – Blrfl
Ho appena testato il tuo codice con 'valgrind --tool = exp-sgcheck' e non sono stati segnalati errori, quale versione di' valgrind' stai usando e quale versione di 'glibc', anche qual è il tuo Linux Distro? –
Puoi dirci qualcosa di più. per esempio. la tua piattaforma, la versione del compilatore, come compilare il codice. – nos