为什么只有当异常转义了当前函数时,std :: function才会导致取消堆栈的堆栈?

问题描述

我正在尝试解决this std::thread bug的问题,这会通过应用noexcept批注来使堆栈在旧版本的gcc中解开:

#include <functional>
#include <stdexcept>

void thrower() {
    throw std::runtime_error("A message is useful but where's my stack?");
}

void run() {
    // Culprit:
    auto j = std::function<void()>([] { thrower(); });
    // Works fine:
    // auto j = [] { thrower(); };
    j();
}

void wrap() noexcept {
    run();
    // Works fine too:
    // auto j = std::function<void()>([] { thrower(); });
    // j();
}

int main() {
    wrap();
}

由于run函数在库中,因此我需要将noexcept应用于包装函数wrap。但是,我观察到,当run函数使用std::function时,堆栈仍处于部分展开状态,并且我看不到关键点告诉我该异常起源于thrower

#0  0x000000000041fb41 in raise ()
#1  0x0000000000401b30 in abort ()
#2  0x00000000004012cb in __gnu_cxx::__verbose_terminate_handler() [clone .cold] ()
#3  0x0000000000403876 in __cxxabiv1::__terminate(void (*)()) ()
#4  0x0000000000414d69 in __cxa_call_terminate ()
#5  0x0000000000403531 in __gxx_personality_v0 ()
#6  0x0000000000416fbe in _Unwind_RaiseException_Phase2 ()
#7  0x0000000000417ab6 in _Unwind_Resume ()
#8  0x0000000000402668 in std::function<void ()>::~function() (this=<optimized out>,__in_chrg=<optimized out>)
    at /usr/include/c++/10/bits/std_function.h:303
#9  run () at main.cpp:10
#10 0x0000000000402671 in wrap () at main.cpp:17
#11 0x000000000040267f in main () at main.cpp:24

请注意第7帧中的_Unwind_Resume和第8帧中的std::function析构函数(后者在gcc 7中也看到了,但在gcc 10中,我必须设置优化级别进行调试才能看到它)。

std::function会导致堆栈解绕,而为什么lambda不会发生这种情况?标准允许吗?我对取消交易的规则了解不多,所以请向我推荐相关资源。

假设我无法修改run,我该怎么做以防止堆栈散开?


更多实验:

如果我改用lambda,我会看到thrower,而不是_Unwind_Resume,而是_Unwind_RaiseException

... (as above) ...
#6  0x0000000000416e5e in _Unwind_RaiseException_Phase2 ()
#7  0x0000000000417630 in _Unwind_RaiseException ()
#8  0x00000000004036c8 in __cxa_throw ()
#9  0x0000000000402575 in thrower () at main.cpp:5
#10 0x0000000000402591 in operator() (__closure=<synthetic pointer>) at main.cpp:13
#11 run () at main.cpp:13
#12 0x000000000040259a in wrap () at main.cpp:17
#13 0x00000000004025a3 in main () at main.cpp:24

如果我将run的主体复制到wrap中,堆栈也就完整了,因此问题似乎专门与调用std::function的转义函数引发的异常有关 not 带有noexcept注释。

... (as above) ...
#11 std::__invoke_impl<void,wrap()::<lambda()>&> (__f=...) at /usr/include/c++/10/bits/invoke.h:60
#12 std::__invoke_r<void,wrap()::<lambda()>&> (__fn=...) at /usr/include/c++/10/bits/invoke.h:153
#13 std::_Function_handler<void(),wrap()::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...)
    at /usr/include/c++/10/bits/std_function.h:291
#14 0x0000000000402680 in std::function<void ()>::operator()() const (this=this@entry=0x7fffffffd780)
    at /usr/include/c++/10/bits/std_function.h:248
#15 0x0000000000402641 in wrap () at main.cpp:20
#16 0x0000000000402667 in main () at main.cpp:24

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...