2

一番下に示されているコードまで、より大きなプログラムを抽出しました。このプログラムを valgrind で実行すると、最終的に次のエラーが報告されます。

==7234== サイズ 4 の無効な読み取り
==7234== 0x34A7275FC8: _IO_file_write@@GLIBC_2.2.5 (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A7275EA1: new_do_write (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A7276D44: _IO_do_write@@GLIBC_2.2.5 (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A7278DB6: _IO_flush_all_lockp (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A7278F07: _IO_cleanup (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A7238BBF: __run_exit_handlers (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A7238BF4: 終了 (/usr/lib64/libc-2.15.so 内)
==7234== by 0x34A722173B: (メインの下) (/usr/lib64/libc-2.15.so 内)
==7234== アドレス 0x542f2e0 は、解放されたサイズ 568 のブロック内の 0 バイトです
==7234== 0x4A079AE: フリー (vg_replace_malloc.c:427)
==7234== by 0x34A726B11C: fclose@@GLIBC_2.2.5 (/usr/lib64/libc-2.15.so 内)
==7234== by 0x40087C: ライター (tc:22)
==7234== by 0x34A7607D13: start_thread (/usr/lib64/libpthread-2.15.so 内)
==7234== by 0x34A72F167C: クローン (/usr/lib64/libc-2.15.so 内)


上記の出力から、これが起こっているようです。

  • main() が戻り、終了ハンドラーの実行を開始して、すべての FILE* を閉じます。
  • まだ実行中の writer() スレッドが起動し、FILE* を閉じます
  • 終了ハンドラーは、現在は無効/free() されている閉じられた FILE* にアクセスしようとします。

私が知る限り、テスト プログラムは未定義のことを何も行いませんが、それについて間違っていれば幸いです。

Valgrind はさまざまな関数にフックするため、glibc ではなく valgrind のバグである可能性があります。

  • これはglibcのバグですか?
  • それともvalgrindのバグですか?

  • それが valgrind か glibc かを判断する方法についてのアイデアはありますか?

tc:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *test(void *arg)
{
    return NULL;
}
void *writer(void *arg)
{
    for(;;) {
        char a[100];
        FILE *f = fopen("out", "w");

        if(f == NULL)
           abort();

        fputs("Test", f);

        if(fgets(a, 100, stdin))
            fputs(a, f);
        fclose(f);  //line 22
    }

    return NULL;
}

int main(int argc, char *argv[])
{
    pthread_t tid1,tid2;


    pthread_create(&tid1, NULL, writer, NULL);
    pthread_create(&tid2, NULL, test, NULL);
    pthread_join(tid2, NULL);
    //pthread_join(tid1, NULL); //no bug if we wait for writer()
    return 0;
}
//compile: gcc t.c -g -pthread

次の場合、valgrind からエラーが発生するまでに数分かかる場合があります。

while [ true ]; do 
  echo test |valgrind --error-exitcode=2 ./a.out  || break  
done  

環境: Fedora 17、glibc-2.15、gcc-4.7.0-5、カーネル 3.5.3-1.fc17.x86_64、valgrind-3.7.0-4

4

1 に答える 1

4

競合状態があります。を呼び出すスレッドがありますexit。これは、開いているすべてのstdioストリームを閉じるように文書化されています。次に、別のスレッドがあり、exitそれを閉じた後、そのようなストリームにアクセスする可能性があります。閉じた後はアクセスできませんFILE*。ゴミを指すことは許可されています。

スレッドが呼び出しをexit危険にさらすようなことをする場合は、を呼び出さないようにする必要がありますexit。とても簡単です。

于 2012-09-23T04:38:46.743 に答える