【发布时间】:2013-08-20 09:44:35
【问题描述】:
我遇到了这个错误,我不太明白这里发生了什么。 我希望coden-p 足以说明我的观点。
我正在修改回调以将我自己的数据注入到对服务器的响应中。
基本上调用堆栈如下所示:
mainRoutine(browseFunction(browseInternal), myBrowseFunction))
^ takes response ^ sends response ^ catches and modifies response
and sends callback
那么会发生什么: 我有一个服务器和几百个静态节点要读取。现在我想支持一个高度动态的消息传递系统,创建一个节点需要 300kb 所以不是一个选项,因为它们是一万个,在几秒钟内创建和删除。因此,我将消息注入到响应中并假装读取了一个节点。
理论就讲这么多。这个系统已经在其他环境下工作了,所以毫无疑问服务器可以处理假响应......
一些代码 - 用 C++ 编写,但使用 C 中的服务器堆栈,没有可用的 new() 或 delete() 方法。所有变量都被初始化并尽可能地填充合理的值。
volatile int pNoOfNodesToAppend = 5;
Boolean xAdapter::Browse(BaseNode *pNode, BrowseContext* pBrowseCtx, int i)
{
[... some initializations....]
BrowseResult* pBrowseResult = &pResponse->Results[i];
int NoOfReferences = pBrowseResult->NoOfReferences + pNoOfNodesToAppend;
pResponse->NoOfResults = NoOfReferences;
// Version one
ReferenceDescription* refDesc = reinterpret_cast <ReferenceDescription *>(realloc(
pBrowseResult->References,
sizeof(OpcUa_ReferenceDescription) * NoOfReferences));
//Version two I tried just out of curiousity to see whether copying "by hand" would cause the programm to crash, as it didn't allocate enough memory - but no problem there.
/*
ReferenceDescription* refDesc = reinterpret_cast <ReferenceDescription *>(malloc( NoOfReferences * sizeof(ReferenceDescription)));
for (int k = 0; k < NoOfReferences; k++)
{
memcpy(&pBrowseResult->References[0], &pBrowseResult->References[k], sizeof(ReferenceDescription));
}
*/
int size = _msize(refDesc);
pBrowseResult->NoOfReferences = NoOfReferences;
if (refDesc != NULL)
{
pBrowseResult->References = refDesc;
}
else
{
return False;
/* Errorhandling ... */
}
[Fill with data... check for errors, handle errors]
return True;
}
我知道这段代码看起来很麻烦,但由于底层堆栈的原因,大部分代码都不能更容易地完成,因为它让我很难来回转换类型,包含大量的结构。
此代码编译并运行良好,一旦发送回调,它就会在 ABABABAB 发生访问冲突而崩溃,我发现这是一个 Microsoft 调试使用的幻数,用于标记 heapAlloc() 内存周围的保护位(前后 4 位)。 见这里:Magic_debug_values 1
编辑:本节已解决。我太盲目了,没有意识到我们在这里谈论的是十六进制,因此太愚蠢了,无法正确计算我的数字。所以除了对cmets的理解之外,认为它不值得一读。
真正让我头疼的是分配的新数组的memsize。
NoOfReferences: 6
sizeof(ReferenceDescription) 0x00000080 unsigned int
(NoOfReferences * sizeof(ReferenceDescription)) 0x00000300 unsigned long
sizeof(*refDesc) 0x00000080 unsigned int //pointer to first element of array
_msize says:
size of (*refDesc) 0x00000300 int
现在为什么新分配的空间大小是 300?如果我的想法不是在欺骗我,那么 6*80 就是 480,即使每个元素周围有 8 个保护位,它仍然是 72*6 > 300 位。无论如何,系统正常进行。
现在在下一段代码中,数组中的结构被填充了有用的数据,并被交还给Response 结构。
回调已发送,服务器将返回到 ServerMain(),然后由于第一次机会和未处理的异常而崩溃
demoserver.exe 中 0x5f95ed6a 处未处理的异常:0xC0000005: 访问冲突读取位置0xabababab。
内存
0x5F95ED6A f3 a5 ff 24 95 84 ee 95 5f 90 8b c7 ba 03 00 00 00 83 e9 04 72 ó¥ÿ$..î._..Ǻ....ƒé.r
0x5F95ED7F 0c 83 e0 03 03 c8 ff 24 85 98 ed 95 5f ff 24 8d 94 ee 95 5f 90 .ƒà..Èÿ$.˜í._ÿ$.”î._.
0x5F95ED94 ff 24 8d 18 ee 95 5f 90 a8 ed 95 5f d4 ed 95 5f f8 ed 95 5f 23 ÿ$..î._.¨í._Ôí._øí._#
0x5F95EDA9 d1 8a 06 88 07 8a 46 01 88 47 01 8a 46 02 c1 e9 02 88 47 02 83 ÑŠ.ˆ.ŠF.ˆG.ŠF.Áé.ˆG.ƒ
0x5F95EDBE c6 03 83 c7 03 83 f9 08 72 cc f3 a5 ff 24 95 84 ee 95 5f 8d 49 Æ.ƒÇ.ƒù.rÌó¥ÿ$..î._.I
0x5F95EDD3 00 23 d1 8a 06 88 07 8a 46 01 c1 e9 02 88 47 01 83 c6 02 83 c7 .#ÑŠ.ˆ.ŠF.Áé.ˆG.ƒÆ.ƒÇ
0x5F95EDE8 02 83 f9 08 72 a6 f3 a5 ff 24 95 84 ee 95 5f 90 23 d1 8a 06 88 .ƒù.r¦ó¥ÿ$..î._.#ÑŠ.ˆ
0x5F95EDFD 07 83 c6 01 c1 e9 02 83 c7 01 83 f9 08 72 88 f3 a5 ff 24 95 84 .ƒÆ.Áé.ƒÇ.ƒù.rˆó¥ÿ$..
0x5F95EE12 ee 95 5f 8d 49 00 7b ee 95 5f 68 ee 95 5f 60 ee 95 5f 58 ee 95 î._.I.{î._hî._`î._Xî.
0x5F95EE27 5f 50 ee 95 5f 48 ee 95 5f 40 ee 95 5f 38 ee 95 5f 8b 44 8e e4 _Pî._Hî._@î._8î._.DŽä
0x5F95EE3C 89 44 8f e4 8b 44 8e e8 89 44 8f e8 8b 44 8e ec 89 44 8f ec 8b .D.ä.DŽè.D.è.DŽì.D.ì.
0x5F95EE51 44 8e f0 89 44 8f f0 8b 44 8e f4 89 44 8f f4 8b 44 8e f8 89 44 DŽð.D.ð.DŽô.D.ô.DŽø.D
0x5F95EE66 8f f8 8b 44 8e fc 89 44 8f fc 8d 04 8d 00 00 00 00 03 f0 03 f8 .ø.DŽü.D.ü........ð.ø
0x5F95EE7B ff 24 95 84 ee 95 5f 8b ff 94 ee 95 5f 9c ee 95 5f a8 ee 95 5f ÿ$..î._.ÿ”î._œî._¨î._
0x5F95EE90 bc ee 95 5f 8b 45 08 5e 5f c9 c3 90 8a 06 88 07 8b 45 08 5e 5f .î._.E.^_ÉÃ.Š.ˆ..E.^_
0x5F95EEA5 c9 c3 90 8a 06 88 07 8a 46 01 88 47 01 8b 45 08 5e 5f c9 c3 8d ÉÃ.Š.ˆ.ŠF.ˆG..E.^_ÉÃ.
【问题讨论】:
-
"现在为什么新分配的空间大小是 300?"。注意,大小是
0x00000300(十六进制),十进制是768。 -
只是为了确定,
ReferenceDescription是 POD(普通旧数据),不是吗?在任何情况下,您都应该考虑使用std::vector。 -
0xABABABAB 听起来确实像“填充捕获模式”,换句话说,C++ 运行时会将其放入缓冲区以捕获对未初始化、已释放或以其他方式“标记为不使用”。换句话说,听起来有些东西正在使用它不应该使用的内存。
-
创建一个testcase 用于调试。然后,当你几天后仍然找不到问题时,在此处发布。
-
Maybe a stub, but this would outweigh the time given to complete the task然后您没有将创建测试的任务分解时间包括在内,这就是您在开始之前就已经失败的地方。重新审视你的时间分配。
标签: c++ callback access-violation realloc