我将一个更大的程序提炼成底部显示的代码。在valgrind中运行这个程序最终会报这个错误:
==7234== 大小为 4 的读取无效 ==7234== 在 0x34A7275FC8:_IO_file_write@@GLIBC_2.2.5(在 /usr/lib64/libc-2.15.so 中) ==7234== 由 0x34A7275EA1:new_do_write(在 /usr/lib64/libc-2.15.so 中) ==7234== 0x34A7276D44:_IO_do_write@@GLIBC_2.2.5(在 /usr/lib64/libc-2.15.so 中) ==7234== 由 0x34A7278DB6:_IO_flush_all_lockp(在 /usr/lib64/libc-2.15.so 中) ==7234== 由 0x34A7278F07:_IO_cleanup(在 /usr/lib64/libc-2.15.so 中) ==7234== 由 0x34A7238BBF:__run_exit_handlers(在 /usr/lib64/libc-2.15.so 中) ==7234== by 0x34A7238BF4:退出(在 /usr/lib64/libc-2.15.so 中) ==7234== by 0x34A722173B: (在 main 下面) (在 /usr/lib64/libc-2.15.so) ==7234== 地址 0x542f2e0 是大小为 568 的块内的 0 个字节 free'd ==7234== 在 0x4A079AE: 空闲 (vg_replace_malloc.c:427) ==7234== by 0x34A726B11C: fclose@@GLIBC_2.2.5 (在/usr/lib64/libc-2.15.so) ==7234== by 0x40087C: writer (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*
- 退出处理程序尝试访问已关闭的 FILE*,它现在是无效/free()'d
据我所知,测试程序没有做任何未定义的事情,但我很乐意在这方面犯错。
Valgrind 与各种功能挂钩,因此它可能是 valgrind 错误而不是 glibc。
- 这是一个 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