【问题标题】:Is there anyway I can prevent throw from calling malloc无论如何我可以防止 throw 调用 malloc
【发布时间】:2016-05-25 00:20:24
【问题描述】:

背景

在我的 C++ 程序中,我有一个 SIGALRM 处理程序,我想在其中通过 throw 将信号转换为异常(我知道这通常不是好的做法,但在我正在处理的系统中,它可能是唯一的选择)。我的问题是,当我们执行 malloc 时,可能会调用 SIGALRM 处理程序,而 throw 将调用执行另一个 malloc 的 __cxa_allocate_exception。在 glibc 2.12 中,这两个 malloc 调用可能会遇到死锁。我尝试预先分配异常,但对 __cxa_allocate_exception 的调用仍然发生。我检查了 gcc 的源代码,似乎没有任何条件可以进行 __cxa_allocate_exception 调用。

附加背景

我在 try 块之前安装信号处理程序,并在 catch 之后将其卸载。我是从信号处理程序中抛出的,这样我认为它将在 try 块内(我们不考虑在 catch 逻辑中接收到信号的情况)并且可以正确捕获。

我想我遇到了这里描述的 malloc 死锁:https://sourceware.org/bugzilla/show_bug.cgi?id=13699 和这里 https://sourceware.org/ml/libc-alpha/2012-02/msg00272.html

问题

我的问题是:无论如何我可以阻止 throw 调用 malloc 吗? (另外,我知道我在做malloc的时候可以阻塞SIGALRM信号,但是我怕阻塞的地方太多了)。

提前致谢。任何帮助/参考都非常感谢。

【问题讨论】:

  • 你打算如何捕捉你抛出的异常?
  • 如果您在析构函数内、在noexcept 函数期间或在另一个异常处于活动状态时收到此信号会发生什么?
  • “将信号转换为异常”?这怎么可能?当信号发生时,信号处理程序不会在任何地方调用 from,因此无法捕获异常。还是我缺少什么?
  • 布赖恩是对的。您究竟希望堆栈在哪里展开?即使实现以某种方式将堆栈展开到异常处理程序,当您从处理信号返回时,程序将如何处理现在无效的堆栈?为什么要这样惩罚自己?
  • 信号处理程序可以异步执行(除非通过专门调用raise 调用)

标签: c++ exception-handling


【解决方案1】:

一般的问题是,如果在任何异步不安全库函数(例如 malloc 或 printf)中调用信号处理程序,跳出信号处理程序(通过 longjmp 或异常)可能会使 glibc 处于不一致状态状态,它会在你下次调用任何东西时崩溃或以其他方式出现异常。

因此,即使您能够避免在异常设置中调用 malloc,并抛出异常并捕获并处理它,您的程序在下次调用 malloc 时仍会崩溃。

避免这种情况的唯一方法是确保在异步不安全库函数中不能调用信号处理程序。您可以通过使用sigblock 来阻止和解除对程序中任何地方的信号不安全函数的每次调用周围的信号:

oldmask = sigblock(SIGALRM);
...call to malloc or printf or whatever...
setsetmask(oldmask);

这是可能的,但不是很实用。

【讨论】:

    【解决方案2】:

    手册指出malloc 是“AS-Unsafe”,这意味着在asychronous signal handlers 内部调用它是不安全的。如果你这样做了,你的程序有未定义的行为。

    【讨论】:

    • malloc 可以很容易地替换。提供可以在信号处理程序处于活动状态时切换到保留块的自定义实现。甚至可以通过在混合中加入一些 RAII 来避免在异常期间切换回来
    • 问题是malloc是从“throw”(调用__cxa_allocate_exception,直接调用malloc)而不是我自己调用的。我实际上是在问我是否可以避免这种情况。
    • @Lonely 无论是您还是库,它仍然会导致未定义的行为,并且死锁是完全可以接受的normal result。我不确定解决方法,因为我不完全了解您的问题。
    • @sleeptightpupper 问题是问如何让标准库不调用malloc
    • @immibis 最直接的方法是不要从信号处理程序中抛出异常。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多