我有一个用R编写的GUI,它使用Tcl / TK包以及一个C.dll,它也使用Tcl库。我对此问题进行了一些研究,它似乎与内存有关。我是一个没有经验的程序员,所以我不确定应该在哪里寻找此内存问题。每个malloc()
调用都有一个匹配的free()
,并且与类似的Tcl_Alloc()
和Tcl_Free()
相同。这个错误也很难重现,因此恐怕我无法提供可重现的示例,因为它本质上看似随机。然而,一种模式是它似乎仅在程序关闭时发生,尽管这是非常不一致的。
通过发表这篇文章,我希望获得一个逻辑过程,人们应该尝试在Tcl / Tk-C-R应用程序的一般情况下调试此问题。我不是在寻找针对我的代码的解决方案,而是在遇到这个问题时个人应该考虑的问题。
编辑:似乎该错误可能源于C代码的这一点,因此我将在此处发布以发表任何评论:
int ogl_loadDownSampleModel(FILE* file, model_t* model)
{
char buffer[1000] = { 0 };
BEG_LING("Surface=");/*set filepointer to tag*/
PLY_ATTR_GET_INT("Surface=", buffer, &model->dsCount); /*read in dsCount value*/
printf("Load down sample model: vertex=%d\n", model->dsCount);
if (model->dsCount <= 0)
{
return 0;
}
FREE(model->dsVertex);
model->dsVertex = (float*)malloc(model->dsCount * 3 * sizeof(float));
/*Read Vertices*/
for (int i = 0; i < model->dsCount * 3; i += 3)
{
fgets(buffer, 300, file);
sscanf(buffer, "%f %f %f", &model->dsVertex[i], &model->dsVertex[i + 1], &model->dsVertex[i + 2]); /*read in downsampled vertices*/
if (i >= 3 * 5)
{
/*handle outliers and grab coords*/
if (model->dsVertex[i] < model->dsMin[X]) model->dsMin[X] = model->dsVertex[i];
if (model->dsVertex[i + Y] < model->dsMin[Y]) model->dsMin[Y] = model->dsVertex[i + Y];
if (model->dsVertex[i + Z] < model->dsMin[Z]) model->dsMin[Z] = model->dsVertex[i + Z];
if (model->dsVertex[i] > model->dsMax[X]) model->dsMax[X] = model->dsVertex[i];
if (model->dsVertex[i + Y] > model->dsMax[Y]) model->dsMax[Y] = model->dsVertex[i + Y];
if (model->dsVertex[i + Z] > model->dsMax[Z]) model->dsMax[Z] = model->dsVertex[i + Z];
model->dsVertex[i] = ogl_calCoordinate(model->dsVertex[i], 0, model->delta);// +0.11;
model->dsVertex[i + 1] = ogl_calCoordinate(model->dsVertex[i + 1], 1, model->delta);
model->dsVertex[i + 2] = ogl_calCoordinate(model->dsVertex[i + 2], 2, model->delta);
}
else
{
/*if no outliers, grab coords*/
model->dsVertex[i] = ogl_calCoordinate(model->dsVertex[i], 0, model->delta);// +0.11;
model->dsVertex[i + 1] = ogl_calCoordinate(model->dsVertex[i + 1], 1, model->delta);// +1.27;
model->dsVertex[i + 2] = ogl_calCoordinate(model->dsVertex[i + 2], 2, model->delta);// -0.02;
}
}
double delta[4] = { 0.0 };
for (int j = 0; j < 3; j++)
{
if (model->dsMax[j] - model->dsMin[j] != 0) { // distinct max/min
delta[j] = (model->dsMax[j] + model->dsMin[j]) / 2; /*midpoint*/
float tmp = POSITIVE(delta[j]) + model->dsMax[j]; //go beyond delta[j] of max
if (tmp > delta[3]) //if our jump exceeds maximum threshold
{
delta[3] = tmp; //set our new threshold to that jump
}
}
printf("min=%f, max=%f, delta[j]=%f\n", model->dsMin[j], model->dsMax[j], delta[j]);
}
for (int i = 15; i < model->dsCount * 3; i += 3)
{
//model->dsVertex[i] = calCoordinate(model->dsVertex[i], 0, delta);
//model->dsVertex[i + 1] = calCoordinate(model->dsVertex[i + 1], 1, delta);
//model->dsVertex[i + 2] = calCoordinate(model->dsVertex[i + 2], 2, delta);
}
return model->dsCount;
}
这里是model_t
的结构:
typedef struct model_t
{
float* vertex;
float* color;
float* normal;
float* dsVertex; //down sample vertex
int count;
int dsCount; //the number of down sample vertex
float max[3];
float min[3];
float dsMax[3];
float dsMin[3];
float delta[4];
} model_t;
该消息来自Ptr2Block()
中的函数tclThreadAlloc.c
(或其他一些消息会产生相同的错误消息;可能,但不太可能),这是Tcl的线程专用内存分配器(在Tcl内部广泛使用,以减少全局锁定被击中的次数)。具体来说就是:
if (blockPtr->magicNum1 != MAGIC || blockPtr->magicNum2 != MAGIC) {
Tcl_Panic("alloc: invalid block: %p: %x %x",
blockPtr, blockPtr->magicNum1, blockPtr->magicNum2);
}
问题?这些零应为MAGIC
(等于0xEF
)。这表明something已覆盖内存块的元数据(还应包括该块的大小,但现在可能是热垃圾),并且程序存储完整性不再受信任。 las,此时,我们现在正在处理处于破裂状态的程序,该状态之前发生了破裂。发生恐慌的地方仅是错误的[[检测发生的地方,而不是错误的实际位置。
everything
的版本并关闭花哨的内存分配器来完成的(在Tcl的代码中,这是通过在构建时定义PURIFY
符号来完成的),然后运行结果代码-希望仍然存在错误-使用electricfence
或purify
之类的工具(因此带有特殊符号名称)来查看发现了哪些类型的越界错误;他们非常擅长解决此类问题。