在退出线程之前在本地指针上调用 free() 会导致无效读取

问题描述 投票:0回答:0

我正在从事一个编程项目,以更好地理解线程之间的同步。我逐行解析文本文件(使用多线程)以读取网站名称 (stackoverflow.com) 并将此名称排入我实现的 FIFO 数据结构中。一旦队列有名称要解析,多个线程就会开始将这些名称从队列中取出并将名称解析为 IP 地址。我使用这篇文章的最佳答案作为逐行阅读的模型。

由于使用了

if (line) free(line);
,所以这个最佳答案有点争议我已经使用valgrind将我的问题追溯到对
free()
的调用。

这里是链接帖子中描述的逐行读取文件的方法:

void *service_file(void *arguments)
{
    req_arg_struct *args = arguments;
    FILE *data_file;
    char *line = NULL;
    size_t len = 0;
    ssize_t read;

    // code omitted to open next data_file in queue

        while ((read = getline(&line, &len, data_file)) != -1)
        {
            if (read <= MAX_NAME_LENGTH)
            {
                en_q(args->shared_array, line);
                fprintf(args->req_log, "Added %s for resolution\n", line);
            }
        }
        fclose(data_file);
        // get next file and repeat
    }
    
    /* 
    Removing the call to free below will completely resolve the problem, 
    but results in memory leak as found using valgrind
    */
    if (line)
        free(line);

    pthread_exit(NULL);
}

其他主题:

void *resolve_addr(void *arguments)
{
    res_arg_struct *args = arguments;

    // code omitted to get next address to resolve
    {
        char ip_addr[MAX_IP_LENGTH];
        // the function below resolves curr_address to ip_addr
        int lookup_res = dnslookup(curr_address, ip_addr, MAX_IP_LENGTH);

        if (lookup_res == 0) // no errors in dnslookup
        {
            fprintf(args->res_log, "%s, %s\n", curr_address, ip_addr); // curr_address prints 
        }

        else // something went wrong, likely curr_address wasn't readable
        {
            fprintf(args->res_log, "%s, NOT_RESOLVED\n", curr_address); // curr_address prints as empty string
        }

        // get next address and continue 
    }

    pthread_exit(NULL);
}

请记住,这些函数作为参数传递给对

pthread_create()
的调用,并且多个线程正在执行上面显示的代码。 FIFO 队列使用信号量进行保护,我已经能够验证这种保护是有效的。在上面的代码上运行 valgrind 会导致许多错误,如下所示:

==21891== Invalid read of size 1
==21891==    at 0x50A5CD0: vfprintf (vfprintf.c:1632)
==21891==    by 0x50AC806: fprintf (fprintf.c:32)
==21891==    by 0x40102A: resolve_addr (multi-lookup.c:84)
==21891==    by 0x4E416B9: start_thread (pthread_create.c:333)
==21891==  Address 0x5428280 is 0 bytes inside a block of size 120 free'd
==21891==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21891==    by 0x400F7E: service_file (multi-lookup.c:61)
==21891==    by 0x4E416B9: start_thread (pthread_create.c:333)
==21891==  Block was alloc'd at
==21891==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21891==    by 0x50C59F7: getdelim (iogetdelim.c:62)
==21891==    by 0x400EFF: service_file (multi-lookup.c:29)
==21891==    by 0x4E416B9: start_thread (pthread_create.c:333)

但达到:

==21891== HEAP SUMMARY:
==21891==     in use at exit: 0 bytes in 0 blocks
==21891==   total heap usage: 1,676 allocs, 1,676 frees, 9,681,222 bytes allocated
==21891== 
==21891== All heap blocks were freed -- no leaks are possible

现在,如果我删除对

free(line)
的调用,代码将按预期工作(
fprintf
适当地写入包含在
line
中的主机名),但是 valgrind 显示:

==21938== HEAP SUMMARY:
==21938==     in use at exit: 600 bytes in 5 blocks
==21938==   total heap usage: 1,550 allocs, 1,545 frees, 9,476,382 bytes allocated
==21938== 
==21938== 600 bytes in 5 blocks are definitely lost in loss record 1 of 1
==21938==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21938==    by 0x50C59F7: getdelim (iogetdelim.c:62)
==21938==    by 0x400EFF: service_file (multi-lookup.c:29)
==21938==    by 0x4E416B9: start_thread (pthread_create.c:333)
==21938== 
==21938== LEAK SUMMARY:
==21938==    definitely lost: 600 bytes in 5 blocks
==21938==    indirectly lost: 0 bytes in 0 blocks
==21938==      possibly lost: 0 bytes in 0 blocks
==21938==    still reachable: 0 bytes in 0 blocks
==21938==         suppressed: 0 bytes in 0 blocks

为什么我释放

fprintf
时调用
line
会出现无效读取?

c multithreading memory-management memory-leaks pthreads
© www.soinside.com 2019 - 2024. All rights reserved.