MFC 程序中的堆损坏
Posted
技术标签:
【中文标题】MFC 程序中的堆损坏【英文标题】:Heap corruption in MFC program 【发布时间】:2012-08-28 07:34:00 【问题描述】:我遇到了程序中的堆损坏问题。在程序中,我正在读取一个数据块并对其执行 FFT 和 IFFT。我正在为 2 个图像(主从图像)做这件事。完全相同的代码对主服务器运行良好,但在我尝试删除从属缓冲区时显示从属文件的堆损坏。
fcomplex 定义为:
typedef struct float real, imag;fcomplex;
附上相关部分代码的sn-p: 完整代码:http://sharetext.org/7xXe
如果我不为从映像调用 fft 和 ifft 函数,则不会发生错误。 (不过对于主人来说一切都很好)
为了调试错误,我安装了应用程序验证程序,但我无法解码日志文件。它在这里:http://sharetext.org/Y2ji(XML 文件复制粘贴)
视觉工作室给出的错误是: 检测到堆损坏:在 0x062C0040 的正常块 (#194456) 之后
CCoarseFun::fcomplex * slave_bfr;
CCoarseFun::fcomplex * slave_col;
slave_bfr = Pcoarse.init_1Dcmplx(SIZE*s_cols);
slave_col = Pcoarse.init_1Dcmplx(SIZE);
Pcoarse.cfft1d_(&SIZE,slave_col,&FFTdir); // This function causes a problem
Pcoarse.complex_mult_col(filter, slave_col, SIZE, slave_col)
Pcoarse.cfft1d_(&SIZE,slave_col,&FFTdir); // As does this one
// delete memory related to slave
delete [] slave_bfr; // Heap corruption here
delete [] slave_col;
让我感到困惑的是代码非常简单,而且它 100% 仅适用于主文件。为什么slave会崩溃?
有人可以指导我找到解决方案,或者也可以提供有关如何使用应用程序验证器的教程吗?
谢谢, 肖纳克
编辑:使用 Win7 x64 - VS2010
编辑 2:init_1Dcmplx 的定义
CCoarseFun::fcomplex* CCoarseFun::init_1Dcmplx(int n)
fcomplex *a;
a=new fcomplex[n];
for(int i=0;i<n;i++)
a[i].real=float(0.0);
a[i].imag=float(0.0);
return a;
EDIT3:cfft1D_ 的代码:http://sharetext.org/hzIg
EDIT4:mem.delfloat() 的代码
void CMemAlloc::del_float(float *a)
if (a!=NULL)
delete[] a;
a=NULL;
else
return;
【问题讨论】:
init_1Dcmplx
是如何定义的?它是否使用new ...[]
来分配结构?
@nneonneo 是的。请参阅 EDIT2
贴出cfft1d_的代码,相关部分。
@lyricat sharetext.org/hzIg
好吧,del_float 不太正确。它正在删除数组,但它并没有像看起来那样将指针设置回 NULL。那是因为它在指针的副本上进行操作。但是之后没有使用指针,所以我认为这不是最终原因。
【参考方案1】:
mem_float() 函数不正确。看起来它在删除后将指针设置为NULL,但它只是在指针的副本上工作,所以调用者的副本仍然指向已删除的内存块。
你可以这样做
delete [] cf;
cf = NULL;
你有几行看起来像这样:
four1(cf-1,nn,isign);
我认为这是在数组开始之前访问内存。
除此之外,four1()
内部的索引非常复杂 - 您必须使用调试器逐步检查它以检查边缘情况。
【讨论】:
我会调查它的行为。然而,对于主文件,这个函数在第一次调用时工作得很好。非常感谢您一直以来的帮助。 没关系,我对索引有误,我已经删除了那部分。 我想看看我可以对那个函数做些什么改变。不过我没有看到问题:该函数为 2*n 值初始化 cf [比如 32]。 “i”将一直到 30,因此索引 31 将有效。对 n 的约束是它必须是 2 的幂,因此代码将是有效的 IMO。编辑:对不起!没有看到你的更新 对不起!我在您发布编辑时输入了该内容!我会调查新问题。 F11'ing :) 改变这个太four1(cf,nn,isign) 会产生一个新的堆错误。但我认为这个解决方案是正确的,至少为我指明了正确的方向。我可能还不能调试 fft 代码。我可以通过某种方式解决它吗?【参考方案2】:首先,了解堆损坏错误告诉您的内容很重要。当您在 Visual Studio 中运行调试版本时,它使用具有调试堆的运行时库的调试版本。每当您使用new
分配一些内存时,它的两侧都会有一些额外的保护字节。当您delete
时,调试堆会检查这些保护字节是否完整,如果没有,则会发出此警告。
假设Pcoarse.init_1Dcmplx()
在堆上分配内存,那么对它的两次调用很可能会一个接一个地分配内存:
XXXXXX - guard bytes
slave_bfr
XYXYXY - these are the guard bytes that are probably being corrupted
slave_cols
XXXXXX
您对slave_cols
执行了操作Pcoarse.cfft1d_()
,但在删除slave_bfr
时出现堆损坏错误。这表明cfft1d_()
在slave_cols
开始之前覆盖了内存,因此它破坏了slave_bfr
的保护字节。
因此,我将查看您的 cfft1d_()
代码中可能存在负数组索引的位置,因为这可能会导致 slave_bfr
中的内存被踩踏。
还可以查看SO answers 的一些有用提示,了解如何充分利用调试堆,尤其是this one,了解如何启用更密集的内存检查。
【讨论】:
感谢您提供信息丰富的帖子。我正在尝试通过您在此页面上提供的链接和其他人的建议进行调试 即使我也简单地调用从属序列也会发生这种情况【参考方案3】:“检测到堆损坏:在 0x062C0040 的正常块 (#194456) 之后”表示您分配了一个块,得到了地址为 0x062C0040 的块 #194456,并且您写入的内存字节比分配的多。所以你有一个经典的缓冲区溢出。您应该考虑用 STL 容器替换指针。在您的情况下,我更喜欢使用std::vector
,而不是使用new float[]
分配的原始浮点数组。 STL 容器可以帮助您在错误访问时立即检测超出边界的写入,而不仅仅是在删除内存块之后。
【讨论】:
我个人本来希望这样做,因为我对指针/原始数组不太满意,但是所有旧代码都使用该结构,包括我需要调用的函数,例如 fft 等。也许我可以尝试分配一个更大的块 - 否则我的分配大小是错误的,因为代码对于 master 运行完美。 如果我用 slave_bfr = Pcoarse.init_1Dcmplx(SIZEs_cols+1) 替换 slave_bfr = Pcoarse.init_1Dcmplx(SIZEs_cols) 它不会给我任何错误。但是在删除语句之后我还有一个 30mb 的块。以上是关于MFC 程序中的堆损坏的主要内容,如果未能解决你的问题,请参考以下文章
0xc0000374 未附加调试时 Cli/Cpp 代码中的堆损坏
混合模式 C++/CLI 崩溃:atexit 中的堆损坏(静态析构函数注册)
MFC 程序挂起:在 Vista 上更新 KB3059317 后 Comctl32.dll 损坏?