8

Invalid read of size 8を使用しているときにValgrind が印刷される理由がわかりませんwchar_t。valgrind-3.7.0 と gcc 4.7.2 で 64 ビット Ubuntu (3.5.0-25) システムを実行しています。

#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;
}

コンパイル:

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

Valgrind の結果:

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

同じことを「作業文字列」で実行すると、次のようになります。

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

問題はありません:

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

最初は、文字列のサイズは常に 8 の倍数である必要があると考えていましたが (一部の wcs は 8 のチャンクを読み取る可能性があります)、場合によっては失敗したため、NULL ターミネータ((wcslen(item) + 2) * sizeof(wchar_t))に常に 8 バイトを追加する必要があると考えました。私のシステムでは4バイトであり、ターミネータsizeof(wchar_t)を処理するのに十分なはずなので、意味がありません。L'\0'

glibc のwcslenソース コードも読みましたが、目新しいものはありません。私は今、Valgrindの問題を考えています。ここに光を投げてみませんか?Valgrind に対してバグを報告する価値はありますか?

ありがとうございました

4

1 に答える 1

6

これはおそらく、wcslen関数のSSE最適化が原因です。たとえば、https://bugzilla.redhat.com/show_bug.cgi?id=798968またはhttps://bugs.archlinux.org/task/30643を参照ください

を最適化する場合wcslen、一度に複数のワイド文字を読み取り、ベクトル化された命令(SSE)を使用してそれらをと比較する方が高速L'\0'です。残念ながら、valgrindはこれを初期化されていない読み取りと見なしますが、の結果はwcslen初期化されていない値に依存しないため、無害です。

修正は、新しいバージョンが誤検知を抑制することを期待してvalgrindを更新することです。

于 2013-03-22T15:07:52.867 に答える