2013-03-22 5 views
8

Ich kann nicht herausfinden, warum Valgrind Invalid read of size 8 bei Verwendung von wchar_t druckt. Ich benutze ein 64bit Ubuntu (3.5.0-25) System mit valgrind-3.7.0 und gcc 4.7.2.wchar_t valgrind issue - Ungültiger Lesewert von Größe 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; 
} 

Compile:

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

Valgrind Ergebnisse:

==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) 

Nun, wenn ich das gleiche, aber mit einem 'Arbeits string' laufen, sagen wir mal,

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 bekomme kein Problem:

==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) 

Zuerst dachte ich, die Stringgröße sollte immer Vielfaches von 8 sein werden (vielleicht einige wcs lesen Stücke von 8), aber einige Fälle, schlug fehl, dann dachte ich, ich würde immer 8 Byte für den Nullabschluss anhängen haben ((wcslen(item) + 2) * sizeof(wchar_t)), es hat funktioniert, aber das macht keinen Sinn, seit sizeof(wchar_t) - in meinem System - ist 4 Bytes und sollte ausreichen, um den L'\0' Terminator zu behandeln.

Ich lese auch den glibc wcslen Quellcode, aber nichts neues. Ich denke jetzt an Valgrind Problem. Könnt ihr hier etwas Licht werfen? Lohnt es sich einen Fehler gegen Valgrind zu stellen?

Danke

+0

Vielleicht ein Problem mit Valgrind, ja. Ich bekomme keine Fehler mit der Version 3.8.1 mit Ihrem Code und der gleichen GCC-Version. – teppic

+0

Ändere dies 'new_text = (wchar_t *) malloc ((wcslen (Text) + 1) * sizeof (wchar_t));' wird 'new_text = Calloc (wcslen (Text) + 1, sizeof (* new_text));' und erneut testen. – alk

+0

Als eine Randnotiz - Ihr Code wird nicht funktionieren, wenn Sie _any_ Nicht-ASCII-Zeichen in Ihren Zeichenfolgen verwenden. Sie sollten das Gebietsschema festlegen. – teppic

Antwort

6

Dies ist wahrscheinlich durch SSE Optimierung der wcslen Funktion verursacht wird; siehe z.B. https://bugzilla.redhat.com/show_bug.cgi?id=798968 oder https://bugs.archlinux.org/task/30643.

Bei der Optimierung von wcslen ist es schneller, mehrere breite Zeichen gleichzeitig zu lesen und vektorisierte Anweisungen (SSE) zu verwenden, um sie mit L'\0' zu vergleichen. Leider sieht Valgrind dies als nicht initialisierten Lesevorgang - was es ist, aber es ist harmlos, weil das Ergebnis von wcslen nicht von dem nicht initialisierten Wert abhängt.

Das Update ist Valgrind in der Hoffnung zu aktualisieren, dass eine neuere Version die falsche positive unterdrücken wird.