我有一个很大的C项目,感谢valgrind,我清理了一些内存管理方面的混乱。除了一件事,我清理了一切,经过一周的分析后,我开始认为这是对我的代码的误解,而不是我的错误。该程序运行良好,但这没有任何意义(我已经看到了程序运行好几周然后因为在int中第31次翻转而卡住的情况)。
我的代码使用了下一个想法:存储(就我的项目而言,"仓库"),它包含我想要构建的所有类型的结构。我使用Xlib中的技巧在内存中保持尽可能小:
typedef struct
{
// data
} TypeA
typedef struct
{
// data
} TypeB
typedef struct
{
// data
} TypeC
typedef union
{
TypeA typea;
TypeB typeb;
TypeC typec;
} UniType;
typedef struct
{
int type;
UniType data;
} Element;
然后我创建一个元素:
SmlErrors SmlWhsAdd(SmlElement element, SmlIndex * index)
{
SML_CHECKPTR(index);
SmlElement * ptrold = warehouse.elem;
warehouse.elem = realloc(warehouse.elem,
(++warehouse.elemcount) * sizeof(SmlElement));
if (!(warehouse.elem))
{
warehouse.elem = ptrold;
*index = 0;
warehouse.elemcount--;
return SML_ERR_BADALLOC;
}
warehouse.elem[warehouse.elemcount - 1] = element;
*index = (warehouse.elemcount - 1);
return SML_ERR_SUCCESS;
}
对于那些认为ptr = realloc的人(ptr ...很糟糕 - 看得更近,我保存旧的并恢复它。我计划用myalloc替换所有的alloc工具将程序崩溃而不是继续工作
这段代码很清楚,valgrind是沉默的。除一例外。我的一个" TypeX"结构(如果确切地说,类型为child-of-TypeX)包含一个数组:
SmlIndex sprite[SML_THEMEBLOCK_SIZE];
每个精灵也是来自仓库的索引,因此它是移动设备中的移动设备,因为该数组是该仓库元素之一(在杰克建造的房屋中)。
我使用前面提到的函数在其中一个sprite中写入值:
SML_CHECKLOC(SmlImageCreate(&(widget->sprite[i]),
widget->geometry.size));
// Which calls `WhsAdd` with `&(widget->sprite[i]` as `index`-parameter.
每当我这样称呼它时,valgrind就会抱怨Invalid write of size 4
。每次我尝试使用sprite[x]
之后的值 - Invalid read of size 4
。如果确切的话,它会抱怨以下这一行:
*index = (warehouse.elemcount - 1);
我的系统是32位,SmlIndex是uint32_t
请给我一个关于挖掘地点的线索。经过一周的研究,我没有想法。这就是为什么我开始认为这可能是valgrind的错误 - 我也听说它在工会和结构中工作很奇怪。
还有一件事。
widget->sprite[i] = 0; // No complainings.
SmlImageCreate(&(widget->sprite[i], ...) // Complainings.
有人可以帮我一把吗?我在沼泽地里淹死了。关于在哪里寻找的任何建议。任何东西。
UPD : MCVE:http://pastebin.com/r5T5ZBPC
此致 亚历克斯。
答案 0 :(得分:1)
(编辑历史记录:MCVE最初使用未初始化的变量,但在初始化所有这些变量后,问题仍然存在)
在MCVE中,问题来自:
SmlWhsAdd(sprite, &(warehouse.elem[window].data.wdg.sprite[0]));
第二个参数是指向先前调用realloc
所分配的空间的指针。
但是,在SmlWhsAdd
函数内,在此空间上调用realloc
,它会分配一个新块并释放旧块。这使得第二个参数指向释放的空间。
要解决此问题,我的建议是审核SmlWhsAdd
的所有用法,并避免传递warehouse.elem
下的指针。
一个选项可能是使用临时变量,然后在调用后分配索引;另一种选择可能是传递一些其他信息,允许SmlWhsAdd
函数在执行realloc
之后计算写入索引的位置;或者如果索引总是在最后,你甚至根本不需要那个参数,因为调用者可以在warehouse.elemcount-1
后执行。{/ p>