记一次HEAP CORRUPTION DETECTED问题及解决

本文讲述了在将C++ SDK封装为C# SDK过程中,遇到在Unity中RGB图像绘制导致内存越界的问题。通过排查和C++代码测试,发现内存访问超出范围,修复方法是在修改内存前添加边界检查。最终解决了跨平台兼容性问题并详细展示了解决方案和各平台表现对比。
摘要由CSDN通过智能技术生成

最近接手了一个同事的代码,主要是实现对C++ SDK的封装,从而提供给Unity客户调用,我们姑且称之为C# SDK。

该C# SDK提供了一个示例demo,大概就是从摄像头获取数据,然后在其上绘制人体关键点,并渲染出来。该demo分为Unity和Winform两个版本,功能相同,细节略有不同。

问题

问题来了,同样的代码,在Winform中表现正常,在Unity中很容易出现下面这个问题:

在这里插入图片描述

排查

经过一番努力之后,大概定位到这部分代码:

//获取图像,通过new unsigned char[buf_sz]
IntPtr pRgb = NativeMethods.Raw16ToRgb24(fg.foregroundData, nw, nh);
...
//在RGB图像上绘制小矩形
NativeMethods.Rgb24DrawRect(pRgb, nw, nh, rect.x, rect.y, 5, 5, 255, 255, 255, 0);
...
//释放图像,通过delete [] p
NativeMethods.DeleteMemPointer(pRgb);

该代码调用C++ SDK中的一个绘制函数,在RGB图像上画一个5x5像素的矩形。

起初走了弯路,因为Winform中表现OK,所以认为是Unity平台的特性导致,感觉很头大,无从下手。
后来检索搜索引擎,看到这样一个类似的问题:
What does “CRT detected that the application wrote to memory after end of heap buffer” mean?
注意到其中的一个答案:
在这里插入图片描述

这似乎解释了上面的两种不同表现,并且类似的是同样在释放内存出现的错误。带着这两个假设,决定跳过C#的部分,直接看C++代码,写了这样一个测试snippet:

	void debug_heap_corrupt(){
		const auto w = 320;
		const auto h = 240;
		unsigned char buf[] = { 0, 0, 0 };
		for (int i = 0; i < w; i++) {
			for (int j = 0; j < h; j++)
			{
				unsigned char* pRgb = new unsigned char[w * h * 3];
				Rgb24DrawRect_(pRgb, w, h, i, j, 5, 5, buf, 0);
				delete[] pRgb;
			}
		}
	}

幸运的是,在VS2017/x64中,得到了相同的现象:
在这里插入图片描述
并且在VS的Debug模式帮助下,得到了此时传递给绘制函数的值:i=316, j=235。这里有一部分值组合可以触发。

解决

下面就是解决这个问题了,此时断定就是内存越界修改。看Rgb24DrawRect_函数,注意到其中对内存的修改,有这么两个循环。每个循环都是将特定位置的像素,修改为指定的值:

int Rgb24DrawRect_(unsigned char* pRgb, int nw, int nh, int nx, int ny, int nWRect, int nHRect, unsigned char* pColorBuf, int nAlign){
	//loop1
	for (j = 0, k = 0; j < m; j++, k += 3)
	{
		memcpy(pPos + k, pColorBuf, 3);
	}
	
	//loop2
	for (i = 1; i < n; i++)
	{
		memcpy(pCur, pPos, k);
		pCur += cbLine;
	}
}

我这里为了快速解决,就采用简单的方式处理了,在修改内存之前,对目的地址进行判断,确保其落在整个RGB图像unsigned char数组范围内,下面是修改后的代码:

int Rgb24DrawRect_(unsigned char* pRgb, int nw, int nh, int nx, int ny, int nWRect, int nHRect, unsigned char* pColorBuf, int nAlign){

#ifdef PTR_SAFETY_CHECK
	//计算RGB图像的安全范围
	const auto * const pRgbEnd = pRgb + nw * nh * 3;
#endif

	//loop1
	for (j = 0, k = 0; j < m; j++, k += 3)
	{
#ifdef PTR_SAFETY_CHECK
		if(pPos + k + 3 <= pRgbEnd )
#endif
		memcpy(pPos + k, pColorBuf, 3);
	}
	
	//loop2
	for (i = 1; i < n; i++)
	{
#ifdef PTR_SAFETY_CHECK
		if (pCur + k <= pRgbEnd)
#endif
		memcpy(pCur, pPos, k);
		pCur += cbLine;
	}
}

附:不同平台运行时表现

Unity(Windows)WinformVS2017(C++)g++ 7.4.0NDK r11c
报错无报错报错无报错无报错
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值