2013-03-22 12 views
8

Non riesco a capire perché Valgrind stia stampando Invalid read of size 8 quando si utilizza wchar_t. Sto usando un sistema Ubuntu a 64 bit (3.5.0-25) con valgrind-3.7.0 e gcc 4.7.2.Problema wchar_t valgrind - Lettura non valida della dimensione 8

#include <stdio.h> 
#include <wchar.h> 
#include <stdlib.h> 
#include <string.h> 

int main() 
{ 
    // const wchar_t *text = L"This is a t"; // no Valgrind error 
    // const wchar_t *text = L"This is a teeeeeeee"; // no Valgrind error 
    const wchar_t *text = L"This is a test"; // Valgrind ERRROR 

    wchar_t *new_text = NULL; 

    new_text = (wchar_t*) malloc((wcslen(text) + 1) * sizeof(wchar_t)); 
    wcsncpy(new_text, text, wcslen(text)); 
    new_text[wcslen(text)] = L'\0'; 

    printf("new_text: %ls\n", new_text); 

    free(new_text); 

    return 0; 
} 

di compilazione:

$ gcc -g -std=c99 test.c -o test 
$ valgrind --tool=memcheck --leak-check=full --track-origins=yes --show-reachable=yes ./test 

Valgrind risultati:

==19495== Memcheck, a memory error detector 
==19495== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==19495== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info 
==19495== Command: ./test 
==19495== 
==19495== Invalid read of size 8 
==19495== at 0x4ED45A7: wcslen (wcslen.S:55) 
==19495== by 0x4ED5C0E: wcsrtombs (wcsrtombs.c:74) 
==19495== by 0x4E7D160: vfprintf (vfprintf.c:1630) 
==19495== by 0x4E858D8: printf (printf.c:35) 
==19495== by 0x4006CC: main (test.c:16) 
==19495== Address 0x51f1078 is 56 bytes inside a block of size 60 alloc'd 
==19495== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==19495== by 0x40066F: main (test.c:12) 
==19495== 
new_text: This is a test 
==19495== 
==19495== HEAP SUMMARY: 
==19495==  in use at exit: 0 bytes in 0 blocks 
==19495== total heap usage: 1 allocs, 1 frees, 60 bytes allocated 
==19495== 
==19495== All heap blocks were freed -- no leaks are possible 
==19495== 
==19495== For counts of detected and suppressed errors, rerun with: -v 
==19495== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2) 

Ora, se corro lo stesso, ma con un 'stringa di lavoro', diciamo

const wchar_t *text = L"This is a t"; // no Valgrind error 
// const wchar_t *text = L"This is a teeeeeeee"; // no Valgrind error 
// const wchar_t *text = L"This is a test"; // Valgrind ERRROR 

I Nessun problema:

==19571== Memcheck, a memory error detector 
==19571== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==19571== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info 
==19571== Command: ./test 
==19571== 
new_text: This is a t 
==19571== 
==19571== HEAP SUMMARY: 
==19571==  in use at exit: 0 bytes in 0 blocks 
==19571== total heap usage: 1 allocs, 1 frees, 48 bytes allocated 
==19571== 
==19571== All heap blocks were freed -- no leaks are possible 
==19571== 
==19571== For counts of detected and suppressed errors, rerun with: -v 
==19571== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2) 

In un primo momento ho pensato che il formato stringa deve essere sempre essere multiplo di 8 (forse alcuni WC leggono pezzi di 8), ma alcuni casi fallito, poi ho pensato che avrei dovuto accodare sempre 8 byte per il terminatore NULL ((wcslen(item) + 2) * sizeof(wchar_t)), ha funzionato, ma non ha alcun senso dal sizeof(wchar_t) - nel mio sistema - è di 4 byte e dovrebbe essere sufficiente per gestire il terminatore L'\0'.

Ho letto anche il codice sorgente di glibc wcslen ma niente di nuovo. Sto pensando al problema di Valgrind. Ragazzi, potreste fare un po 'di luce qui? Vale la pena di presentare un bug contro Valgrind?

Grazie

+0

Forse un problema con valgrind, sì. Non ho errori con la versione 3.8.1 con il tuo codice e la stessa versione di gcc. – teppic

+0

Cambia questo 'new_text = (wchar_t *) malloc ((wcslen (testo) + 1) * sizeof (wchar_t));' diventa 'new_text = calloc (wcslen (testo) + 1, sizeof (* new_text)); ' e ripetere il test. – alk

+0

Come nota a margine: il codice non funzionerà se si utilizzano _any_ caratteri non ASCII nelle stringhe. Dovresti impostare il locale. – teppic

risposta

6

Questo è probabilmente causato da SSE ottimizzazione della funzione wcslen; vedere per es. https://bugzilla.redhat.com/show_bug.cgi?id=798968 o https://bugs.archlinux.org/task/30643.

Quando si ottimizza wcslen, è più veloce leggere più caratteri di larghezza alla volta e utilizzare le istruzioni vettoriali (SSE) per confrontarli con L'\0'. Sfortunatamente Valgrind lo vede come una lettura non inizializzata, che è, ma è innocua perché il risultato di wcslen non dipende dal valore non inizializzato.

La correzione consiste nell'aggiornare Valgrind nella speranza che una versione più recente sopprima il falso positivo.

Problemi correlati