glibc的,而退出收盘FILE *之间可能的竞争条件?(glibc, possible race

2019-09-22 20:19发布

我蒸一个较大的程序下来,在底部显示的代码。 在Valgrind的运行这个程序最终将报告此错误:

==7234== Invalid read of size 4
==7234==    at 0x34A7275FC8: _IO_file_write@@GLIBC_2.2.5 (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A7275EA1: new_do_write (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A7276D44: _IO_do_write@@GLIBC_2.2.5 (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A7278DB6: _IO_flush_all_lockp (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A7278F07: _IO_cleanup (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A7238BBF: __run_exit_handlers (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A7238BF4: exit (in /usr/lib64/libc-2.15.so)
==7234==    by 0x34A722173B: (below main) (in /usr/lib64/libc-2.15.so)
==7234==  Address 0x542f2e0 is 0 bytes inside a block of size 568 free'd
==7234==    at 0x4A079AE: free (vg_replace_malloc.c:427)
==7234==    by 0x34A726B11C: fclose@@GLIBC_2.2.5 (in /usr/lib64/libc-2.15.so)
==7234==    by 0x40087C: writer (t.c:22)
==7234==    by 0x34A7607D13: start_thread (in /usr/lib64/libpthread-2.15.so)
==7234==    by 0x34A72F167C: clone (in /usr/lib64/libc-2.15.so)


从上面的输出,这似乎是发生了什么:

  • main()的返回,并开始运行退出处理程序关闭所有FILE *
  • 作家()的线程,仍在运行,唤醒,关闭文件*
  • 退出处理程序试图访问所述闭合FILE *,这是现在无效/免费()倒是

据我所知,测试程序没有做任何事情不确定的,但我很乐意吃亏的。

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

Answer 1:

你有一个竞争条件。 您有一个调用线程exit ,这是记录在案,以关闭所有打开的标准输入输出流。 然后,您有另一个线程,之后可能exit已经关闭它,这样的访问流。 您无法访问FILE*它关闭后-它允许指向垃圾。

如果一个线程做一些事情,使得调用exit不安全的,你必须确保你不叫exit 。 它就是这么简单。



文章来源: glibc, possible race condition between closing FILE* while exiting?