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
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
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
Come nota a margine: il codice non funzionerà se si utilizzano _any_ caratteri non ASCII nelle stringhe. Dovresti impostare il locale. – teppic