调用 new(堆)后意外的汇编代码引发异常
我正在追踪一个异常,该异常是从编译器在每次调用 new 后添加的部分代码引发的。这是标准的 C++ new,它应该从堆中获取一些内存并调用类的构造函数。
我们在 SH4 处理器上运行 VxWorks 5.5.1 和 GCC 2.95(或 2.96 不确定)。在 SNiFF+ 4.1 Patch 1 中编译。C
++ 代码如下所示。
CBlocksFile* pBlockFile = new CBlocksFile(szHeaderFile, szDataFile);
生成的汇编代码在调用new之后具有终止/删除/抛出处理。这种模式似乎适用于所有对 new 的调用。
// call to "new"
c4d6000 d14d mov.l @(0x134,pc),r1 (= 0x0c06c1e0 = ___builtin_new)
c4d6002 410b jsr @r1
c4d6004 e414 (mov #20,r4)
...
// compiler generates throw path address
c4d6022 d246 mov.l @(0x118,pc),r2 (= 0x0c4d6034)
...
// and pushes it to the stack
c4d602c 1121 mov.l r2,@(4,r1)
...
c4d6030 a002 bra +4 (==> 0x0c4d6038 : GOOD_PATH)
...
// throw path (there is no visible jump to this address)
c4d6034 a088 bra +272 (==> 0x0c4d6148 : THROW_PATH)
...
GOOD_PATH:
...
// call to constructor
c4d6058 d139 mov.l @(0xe4,pc),r1 (= 0x0c4d1730 T ___Q211CBlocksFilePCcT1bUcl)
...
c4d6060 410b jsr @r1
...
// normal path
return
THROW_PATH:
...
// same pattern again, compiler generates terminate path address
c4d6164 d22f mov.l @(0xbc,pc),r2 (= 0x0c4d6172)
...
// and pushes it to the stack
c4d616a 1121 mov.l r2,@(4,r1)
...
c4d616e a002 bra +4 (==> 0x0c4d6176 : NO_TERMINATE)
...
c4d6172 a039 bra +114 (==> 0x0c4d61e8 : TERMINATE_A)
...
NO_TERMINATE:
...
// delete handling
if ( ?? )
c4d617c 2118 tst r1,r1
c4d617e 8d04 bt/s +8 (==> 0x0c4d618a)
...
{
delete ??
...
c4d6184 d128 mov.l @(0xa0,pc),r1 (= 0x0c06be20 = ___builtin_delete)
c4d6186 410b jsr @r1
...
}
c4d618a 9044 mov.w @(0x88,pc),r0 (= 0x0000028c)
c4d618c 02ee mov.l @(r0,r14),r2
c4d618e 5121 mov.l @(4,r2),r1
c4d6190 6112 mov.l @r1,r1
c4d6192 1211 mov.l r1,@(4,r2)
c4d6194 d125 mov.l @(0x94,pc),r1 (= 0x0c06a880 = ___sjthrow)
c4d6196 410b jsr @r1
这段代码有什么用处?它看起来不像无内存情况,因为 throw 不在新函数内。
为什么要调用 throw?来自谁?这种将代码地址放入堆栈的模式有两次,该地址可能会在以后执行时使用。
谢谢
I am chasing an exception which is thrown from a part of code which is added by the compiler after each call to new. It's the standard C++ new, which should get some memory from the heap and call the constructor of the class.
We are running VxWorks 5.5.1 with GCC 2.95 (or 2.96 not sure about that) on a SH4 processor. Compiled within SNiFF+ 4.1 Patch 1.
The C++ codes looks like this.
CBlocksFile* pBlockFile = new CBlocksFile(szHeaderFile, szDataFile);
And the generated assembler code has a terminate/delete/throw handling after the call to new. This pattern seems to be applied on all calls to new.
// call to "new"
c4d6000 d14d mov.l @(0x134,pc),r1 (= 0x0c06c1e0 = ___builtin_new)
c4d6002 410b jsr @r1
c4d6004 e414 (mov #20,r4)
...
// compiler generates throw path address
c4d6022 d246 mov.l @(0x118,pc),r2 (= 0x0c4d6034)
...
// and pushes it to the stack
c4d602c 1121 mov.l r2,@(4,r1)
...
c4d6030 a002 bra +4 (==> 0x0c4d6038 : GOOD_PATH)
...
// throw path (there is no visible jump to this address)
c4d6034 a088 bra +272 (==> 0x0c4d6148 : THROW_PATH)
...
GOOD_PATH:
...
// call to constructor
c4d6058 d139 mov.l @(0xe4,pc),r1 (= 0x0c4d1730 T ___Q211CBlocksFilePCcT1bUcl)
...
c4d6060 410b jsr @r1
...
// normal path
return
THROW_PATH:
...
// same pattern again, compiler generates terminate path address
c4d6164 d22f mov.l @(0xbc,pc),r2 (= 0x0c4d6172)
...
// and pushes it to the stack
c4d616a 1121 mov.l r2,@(4,r1)
...
c4d616e a002 bra +4 (==> 0x0c4d6176 : NO_TERMINATE)
...
c4d6172 a039 bra +114 (==> 0x0c4d61e8 : TERMINATE_A)
...
NO_TERMINATE:
...
// delete handling
if ( ?? )
c4d617c 2118 tst r1,r1
c4d617e 8d04 bt/s +8 (==> 0x0c4d618a)
...
{
delete ??
...
c4d6184 d128 mov.l @(0xa0,pc),r1 (= 0x0c06be20 = ___builtin_delete)
c4d6186 410b jsr @r1
...
}
c4d618a 9044 mov.w @(0x88,pc),r0 (= 0x0000028c)
c4d618c 02ee mov.l @(r0,r14),r2
c4d618e 5121 mov.l @(4,r2),r1
c4d6190 6112 mov.l @r1,r1
c4d6192 1211 mov.l r1,@(4,r2)
c4d6194 d125 mov.l @(0x94,pc),r1 (= 0x0c06a880 = ___sjthrow)
c4d6196 410b jsr @r1
For what is this code snipped useful? It does not look like the no memory condition, because the throw is not within the new function.
Why is the throw called? And from whom? There is twice this pattern of putting a code address onto the stack, which might be used for execution later on.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
猜测是应用此模式是因为 c++ 要求如果构造函数抛出异常,则应释放该对象的内存。因此,如果构造函数内部抛出异常,新分配的对象将被删除。
您始终可以尝试从对象的构造函数中显式抛出一些内容,以查看执行的路径,以验证该答案是否有用。
A guess would be that this pattern is applied because it is a requirement of c++ that if the constructor throws, the memory for the object should be freed. So if an exception is thrown from within the constructor, the newly allocated object gets deleted.
You could always try to explicitly throw something from the constructor of your object to see which path execution takes to verify whether or not this answer is useful.
我想在问题解决后快速回答我自己的问题。
我添加了一个新的故障处理程序以查看是否会调用它。它是在抛出上述异常之前调用的。所以它变成了“内存不足的情况”,几个小时内我就发现了内存泄漏。
似乎在 VxWorks 中,如果内存不足情况后抛出异常,您不会在堆栈跟踪中看到“新”函数调用。
感谢 DumpCoder 和 villintehaspam,他们让我思考到了正确的方向。
I want to give a quick answer to my own question after the issue is solved.
I've added a new failure handler to see if it would be called. And it was called right before the mentioned exception would have been thrown. So it turned into an 'out of memory condition' and within a few hours I've found the memory leak.
It seems that in VxWorks you don't see the 'new' function call in the stack trace in case of an exception thrown after an out of memory condition.
Thanks to DumpCoder and villintehaspam, they made me thinking into the right direction.