调用 new(堆)后意外的汇编代码引发异常

发布于 2024-10-08 18:12:24 字数 2371 浏览 1 评论 0原文

我正在追踪一个异常,该异常是从编译器在每次调用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

时光病人 2024-10-15 18:12:24

猜测是应用此模式是因为 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.

烧了回忆取暖 2024-10-15 18:12:24

我想在问题解决后快速回答我自己的问题。

我添加了一个新的故障处理程序以查看是否会调用它。它是在抛出上述异常之前调用的。所以它变成了“内存不足的情况”,几个小时内我就发现了内存泄漏。

似乎在 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文