1

我的代码中有一些链接列表。每个链表是 C 代码中大型结构的一部分,它是函数的局部变量。该代码使用另一个函数来填充列表,执行一些其他操作,然后调用第三个函数来打印和删除它。第一个节点不需要删除。

问题: 该函数正确打印所有数据,因此没有悬空指针等。但是当我尝试释放内存时,出现堆损坏错误。引发此错误的代码示例是:

flag = 0;

while( stpBS_current != NULL && stpFlags_current != NULL ){
// Linked list printing code is removed for clarity
    if( flag == 1 ){
        stpPrev = stpBS_current;
        stpFlags_prev = stpFlags_current;

        stpBS_current = (struct BasicService *)stpBS_current->pNext;
        stpFlags_current = (struct BasicService_Flags *)stpFlags_current->pNext;

        free( stpPrev );
        free( stpFlags_prev );
    }
    else
    {
        stpBS_current = (struct BasicService *)stpBS_current->pNext;
        stpFlags_current = (struct BasicService_Flags *)stpFlags_current->pNext;

        flag = 1;
    }
}

stpPrevstpFlags_prev是局部变量,stpBS_currentstpFlags_current打印/删除函数中作为参数传递。执行强制转换是因为原始链表具有void *. 由于相同的函数正确打印了所有存储的数据,并且该内存尚未在其他地方释放,所以我确定指针是正确的。

我在这里完全不知所措。Google 上的所有内容都与缓冲区溢出有关,但我确信情况并非如此。我正在使用 MS Visual C++ 2010,它显示的错误是:

Windows 在 ZTE Parser [24.04.2012].exe 中触发了断点。

这可能是由于堆损坏,这表明 ZTE Parser [24.04.2012].exe 或其已加载的任何 DLL 中存在错误。

这也可能是由于用户在 ZTE Parser [24.04.2012].exe 具有焦点时按 F12。

当然我没有按F12,所以这是不可能的。如果我忽略第一个错误并继续代码的执行,那么在它返回之前我会从同一次调用中得到几个断言失败,free()并最终得到:

MS VS 2010 堆损坏快照

空指针是罪魁祸首吗?但毕竟 malloc() 和 free() 使用 void 指针,所以 IMO 这应该不是问题。我相信堆是一个全局内存,所以在不同的函数中分配和取消分配应该不是问题。

分配内存的代码很简单(2个链表)。为了清楚起见,我删除了头节点初始化代码:

stpBSC_current->pNext   =   malloc( sizeof(struct BasicServiceCode) );
stpFlags_current->pNext =   calloc( 1, sizeof(struct BasicServiceCode_Flags) );

if( stpBSC_current->pNext == NULL || stpFlags_current->pNext == NULL )
    exit( 1 );
else
{
    stpBSC_current      =   (struct BasicServiceCode *)stpBSC_current->pNext;
    stpFlags_current    =   (struct BasicServiceCode_Flags *)stpFlags_current->pNext;
}

我认为如果内存分配或链接列表管理中存在任何漏洞,那么在打印列表时应该出现错误,或者至少某些数据必须作为垃圾出现,但它工作得很好。当我尝试释放内存时出现错误。任何帮助和想法将不胜感激。提前致谢。

4

3 回答 3

1

结果表明标志条件不正确(问题中未显示某些打印代码)。

原因:试图free()释放没有使用分配的头节点malloc()。这是一个静态分配的变量。因此,从技术上讲,这并不是最初错误所暗示的堆损坏,而是指定的断言失败错误,free()它试图释放位于堆缓冲区开始之前的一些内存,当然是在堆栈上。这是导致错误的原因。

@everyone 感谢您的帮助和建议。

于 2012-10-30T08:09:29.057 回答
0

仅仅因为您可以打印数据并不意味着您没有损坏堆。当您释放内存时,数据会一直保留在那里,直到内存被再次分配并被覆盖。因此,您的链表可能包含指向已释放内存的指针,您仍然可以读取它,但稍后会遇到问题。

于 2012-10-25T15:11:18.627 回答
0

这几乎肯定是由缓冲区溢出引起的:这会导致您的代码覆盖堆控制信息,这些信息可能存储在您分配的内存块之前和/或之后。在您尝试释放内存之前,可能不会检测到此类错误。

需要考虑的事项:

如果您正在解析数据(正如程序名称所暗示的那样),您确定将解析后的输入复制到的缓冲区足够大吗?

结构 BasicServiceCode 和 BasicServiceCode_Flags 是否包含任何 C 样式的字符串?如果是这样,您很可能会遇到缓冲区溢出。特别注意空终止符。

于 2012-10-27T08:17:41.507 回答