为什么valgrind和gdb指向不同的代码行?或者:如何在循环中将malloc()和free()指针指针?

时间:2018-08-07 15:03:03

标签: c++ gdb valgrind

以下代码中的循环可以执行几次,但随后崩溃。

#include <cstdlib>
#include <iomanip>

using namespace std;

int main(int argc, char *argv[])
{
    //not needed but program will not crash if I remove it
    int blocksize=stoi(argv[1]);
    //typical value 70-100
    int min_length=stoi(argv[2]);

    for(int i=0;i<250000;i++)
    {
        //Allocate memory for new integer array[row][col]. First allocate the memory for the top-level array (rows).
        int **output_std = (int**) malloc(20*sizeof(int*));

        //Allocate a contiguous chunk of memory for the array data values.
        output_std[0] = (int*) malloc( min_length*20*sizeof(int) );

        //Set the pointers in the top-level (row) array to the correct memory locations in the data value chunk.
        for (int k=1; k < 20; k++) 
        {
            output_std[k] = output_std[0]+k*min_length;
        }      

        //do something with output_std


        //free malloc'd space
        free(output_std[0]);
        for(int k=0;k<20;k++)
        {
            output_std[i]=NULL;
        }
        free(output_std);
        output_std=NULL;
    }

    return 0;
}

使用GDB进行调试指向第36行:free(output_std);。 使用valgrind进行调试会产生以下错误:

nvalid write of size 8
==32161==    at 0x4031A0: main (test.cpp:31)
==32161==  Address 0x82f2620 is 0 bytes after a block of size 160 alloc'd
==32161==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32161==    by 0x403159: main (test.cpp:16)

第16行是:int **output_std = (int**) malloc(20*sizeof(int*));

第31行是:free(output_std[0]);

为什么我的代码在错误中的位置不同?

在这种情况下如何进行?

(如何修复我的代码?)

编辑:这些行是正确的。第三方库需要这样的对象。

2 个答案:

答案 0 :(得分:4)

Valgrind通常可以更早地发现问题。那就是使用它的重点。 Valgrind通常会发现问题的根源(或更接近问题的根源),而在GDB中,您只能看到问题的根源。

在您的情况下,问题的根源是由于越界写入数组而导致的堆内存损坏。结果是该堆损坏导致free内部崩溃。 Valgrind抓住了前者。当您运行程序时(例如在GDB下),您只能看到后者。

在您的代码中

    for(int k=0;k<20;k++)
    {
        output_std[i]=NULL;
    }

预期的迭代变量为k。但是您正在i处访问数组。此时i显然是20,这导致valgrind捕获了越界访问。

无论如何,我想说这个循环是毫无意义的:您正在尝试将即将要释放的内存归零。可以提供一些理由说明为什么这样做有意义。但是在库的调试版本中,这样的事情在内存释放函数内部更合适。在用户级代码中,它只会使代码杂乱无章。

P.S。无论如何,您显然张贴了无效的行号。如果free(output_std)是第36行,那么valgrind应该将有问题的行视为34,而不是31。请下次发布准确的代码,并努力准确地确定有问题的行。

答案 1 :(得分:1)

valgrind用自己的检测版本替换了内存分配和释放函数。您可以在输出中看到这一点:

at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

这就是为什么在valgrind下应用程序可能在其他地方崩溃的原因。