valgrind发现难以置信的无效写入和读取次数

时间:2017-05-19 14:24:17

标签: c arrays pointers valgrind

valgrind的新手,我试图理解为什么valgrind在我的一个C程序中发现了大量无效的写入和读取。它首先报告函数调用的无效写入,其中指向数组的调用指针和数组本身已经在main中分配了适当的内存。更令人费解的是,它继续反对这个函数中的许多行,其中声明的双精度值被赋值。

我的C程序针对实验数据改进(即改进)肌肉的跨桥循环模型(微小蛋白质马达反复与另一种蛋白质的细丝相互作用以产生力和运动的事件的循环)。该程序通过基于下坡单纯形法的模拟退火进行,所需函数取自C中的数字配方。

每个模型由19个参数x [1]到x [19]定义。通过首先将x声明为指向double的指针,然后创建一个从1到19的数组,将内存分配给main中的数组。

double *x;
x=dvector(1,19);

然后从19个参数中分配值,最初来自猜测,然后使用基于先前历史的算法:

for (j=1;j<=19;j++)
{
    x[j]=initial_guess;
}

然后将指向x数组的指针传递给函数得分模型,该函数得分模型以多种方式测试模型的机械属性,每个方法产生一个得分,加权平均得分y在第629行传递回main:

y=scoremodel(x);

我的程序第932行的scoremodel声明是

double scoremodel(double *x)

(我也试过

double scoremodel(double x[])

但是valgrind的结果是相同的)

Main然后从先前的结果和下坡单面/模拟退火算法得出下一个应该测试的新模型。

在我上次发布Stack Overflow之后,Mark Setchell得到了很多帮助,我现在能够使用gcc-4.9和-fopenmp标志编译我的程序,这样我就可以在MacPro上使用OpenMP运行它了。使用Yosemite OS x 10.10.5进行操作。它运行时没有崩溃或悬挂。大多数连续模型的属性和分数是完全合理的,单独使用这些程序确实可以明显地改进起始模型。但奇怪的是,大约五分之一的模型具有荒谬的属性和非常差的分数。

我调用了当前版本的valgrind来检测我的程序的较短测试版本中的内存错误,名为refinemadpmodelinc2,并带有命令

 valgrind-3.12.0/bin/valgrind --leak-check=yes ${HOME}/bin  /refinemadpmodelinc2 inc2_49 model3 model4 0 0.9 20 ../../tls/kappaFHStrunc

Valgrind报告程序中的第一个错误发生在我声明函数scoremodel的行。

Invalid write of size 8
==33173==    at 0x100001F71: scoremodel (refinemadpmodelinc2.c:932)
==33173==    by 0x100001D8A: main (refinemadpmodelinc2.c:629)
==33173==  Address 0x1045029a8 is on thread 1's stack
==33173==  in frame #0, created by scoremodel (refinemadpmodelinc2.c:932)

我认为大小为8的无效写入是由于我试图写一个双精度或指向不可用内存的指针,因为它们的大小在我的计算机上都是8个字节。但我不明白我的函数调用有什么问题。

函数中的下几百行,几乎所有变量声明都是由valgrind传递的,但是从第1109行传递到第1203行,每个非空白行都被认为是大小为8的无效写入,尽管大多数这些行都是只是简单的作业,例如

exppower=395.9;

(当exppower已被声明为double时)。我的预感是,虽然我在调用函数得分模型和扰乱valgrind时出错,但这些行肯定是可以的。你非常感谢你帮助我了解valgrind的奥秘。

1 个答案:

答案 0 :(得分:1)

在这种情况下,Valgrind不太可能出错。

旧版本的“Numerical Recipes”使用Fortran约定,从1到 size 包含数组,在C和C ++中分配一个额外的,未使用的元素。本书的最新版本(第三版,仅限C ++)已经废除了所有这些基于1的数组内容(尽管它仍然远不是一个如何编写C ++的光辉例子)。但是,如果您使用基于0的数组混合使用Numerical Recipes和任何形式的更传统的C或C ++,这仍然是一个陷阱。