valgrind 报告 "Invalid write of size 8"

valgrind reporting "Invalid write of size 8"

我正在尝试追踪 valgrind 在某些代码中发现大小为 8 的无效写入的位置,但我很难看到它。我确定 valgrind 是正确的,我只是看不到它。我通过删除函数并使用以下代码或多或少地执行相同的操作来重现原始错误:

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

double* do_realloc(double* orig_graph, int graph_width, int* graph_allocated)
{
    double *graph = (double *)(realloc(orig_graph, (graph_width + 1) * sizeof(*graph)));
    printf("reallocing graph from %d to %d\n", *graph_allocated, graph_width);
    if (!orig_graph) {
        /* initialize */
        memset(graph, 0, graph_width * sizeof(double));
    } else if (graph) {
        if (graph_width > *graph_allocated) {
            /* initialize the new region */
            printf("old region: %p, new region: %p, offset: %d, length: %d\n", orig_graph, graph,
                 (*graph_allocated * sizeof(double)),
                 (graph_width - *graph_allocated) * sizeof(*graph));
            memset(graph + (*graph_allocated * sizeof(*graph)),
                   0,
                   (graph_width - *graph_allocated) * sizeof(*graph));
        }
    } else {
        printf("reallocing FAILED\n");
        graph = orig_graph;
        graph_width = *graph_allocated;
    }

    *graph_allocated = graph_width;
    return graph;

}

int main()
{
    double* graph = NULL;
    int allocated = 0;

    graph = do_realloc(graph, 307, &allocated);
    graph = do_realloc(graph, 300, &allocated);
    graph = do_realloc(graph, 307, &allocated);

}

valgrind 输出为:

$ valgrind ./t 
==4250== Memcheck, a memory error detector
==4250== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4250== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4250== Command: ./t
==4250== 
reallocing graph from 0 to 307
reallocing graph from 307 to 300
reallocing graph from 300 to 307
old region: 0x51d4e60, new region: 0x51d5800, offset: 2400, length: 56
==4250== Invalid write of size 8
==4250==    at 0x4C348BE: memset (vg_replace_strmem.c:1094)
==4250==    by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250==    by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250==  Address 0x51da300 is 16,672 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250== 
==4250== Invalid write of size 8
==4250==    at 0x4C348E6: memset (vg_replace_strmem.c:1094)
==4250==    by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250==    by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250==  Address 0x51da320 is 16,704 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250== 
==4250== Invalid write of size 8
==4250==    at 0x4C348F3: memset (vg_replace_strmem.c:1094)
==4250==    by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250==    by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250==  Address 0x51da328 is 16,712 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250== 
==4250== Invalid write of size 8
==4250==    at 0x4C348FD: memset (vg_replace_strmem.c:1094)
==4250==    by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250==    by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250==  Address 0x51da330 is 16,720 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250== 
==4250== 
==4250== HEAP SUMMARY:
==4250==     in use at exit: 2,456 bytes in 1 blocks
==4250==   total heap usage: 4 allocs, 3 frees, 8,336 bytes allocated
==4250== 
==4250== LEAK SUMMARY:
==4250==    definitely lost: 2,456 bytes in 1 blocks
==4250==    indirectly lost: 0 bytes in 0 blocks
==4250==      possibly lost: 0 bytes in 0 blocks
==4250==    still reachable: 0 bytes in 0 blocks
==4250==         suppressed: 0 bytes in 0 blocks
==4250== Rerun with --leak-check=full to see details of leaked memory
==4250== 
==4250== For counts of detected and suppressed errors, rerun with: -v
==4250== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 0 from 0)

原代码远不止这些,我目前只是想解决第一个问题,其他问题会继续研究。我认为这与主应用程序每次都在此时崩溃有关。

(有人删除了 "C" 标签,因为我留下了一些 C++ 主义,但在我看来这没有达到目的,所以我删除了所有 C++ 主义并得到了相同的结果。)

根据我对发布的代码的分析,

问题出在对 memset() 的调用中(与大多数 valgrind 错误消息一起出现。)

在分配的内存区域末尾写入 sizeof(double)

并且在退出程序之前未能将分配的内存传递给 free()