问题标签 [stack-unwinding]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 到达展开处理程序
知道为什么代码看起来像这样
生成以下机器码
特别是,在无条件之后,我看不到任何通往该行的路径jmp .L11
(这是在编译器资源管理器上生成的没有优化的 GCC 6.2)
为了比较,clang 5.0.0 产生
再次无条件跳转到 return 块,并且 unwind 块(从 second 开始lea rdi
)似乎无法到达。
c++ - 工作线程中的 C++ 未捕获异常
主线程和另一个 std::thread 的未捕获异常行为不同。
这是测试程序
以上代码(C++11),由 GCC 5.4 编译,不带参数运行
运行 1 个参数:
所以堆栈展开是在工作线程中执行的,而不是在主线程中执行的,为什么?
我问是因为我希望核心转储在两种情况下都提供有用的堆栈回溯信息(对于未捕获的异常)。
提前致谢!!!
进一步的试验表明,在线程函数体 mytest() 中添加noexcept关键字可以部分解决我的问题,因为 unwind 会失败,但这不是一个好的解决方案,因为如果 mytest() 在没有 noexcept 保证并实际抛出的情况下调用另一个函数,unwind 仍然会部分发生未捕获的异常。
更新:感谢所有评论提供者,现在我了解 C++ 异常对回溯不友好,并且 GCC 作为 C++ 实现,可以自由选择在从主线程抛出未捕获的异常时不展开,并在从工作线程时展开。
更新:特别感谢 Sid S 和 Jive Dadson,我必须混淆一些概念:1)异常/错误处理;2) 运行时断言 3) 段错误,2&3 类似,它们是不可恢复的错误,立即中止是唯一的选择,它们在调试器中也对回溯友好,因为不涉及堆栈展开。它们根本不应该使用异常概念来实现。应该始终捕获异常,不推荐使用离开 main() 的未捕获异常。
c++ - 获取销毁期间捕获的错误的 RAII 方法
在 Wikipedia 上文件 I/O 的 RAII 的典型示例中,关闭文件时发生的任何错误都会被吞没:
file
自动关闭时似乎无法确定是否发生错误;显然,只能file.rdstate()
在file
范围内调用。
我可以file.close()
手动调用,然后检查错误,但我必须在从范围返回的每个地方都这样做,这违背了 RAII 的目的。
一些人评论说,在析构函数中只会发生文件系统损坏等不可恢复的错误,但我不认为这是真的,因为 AFAIK 析构函数在关闭文件之前会刷新文件,并且在刷新时可能会发生可恢复的错误。
那么有没有一种常见的 RAII 方法来获取销毁期间发生的错误?我读到从析构函数中抛出异常是危险的,所以这听起来不像是正确的方法。
我能想到的最简单的方法是注册一个回调函数,如果在销毁期间发生任何错误,析构函数将调用该回调函数。令人惊讶的是,似乎并没有为此提供支持的事件ios_base::register_callback
。这似乎是一个重大的疏忽,除非我误解了什么。
但也许回调是现代类设计中在销毁期间获得错误通知的最常见方式?
我假设在析构函数中调用任意函数也是危险的,但也许将调用包装在一个try/catch
块中是完全安全的。
c++ - 异常堆栈展开的参考参数
在我的代码中,我将 a 传递*this
给 a method foo(const MyClass& arg)
。在这个 foo 的深处抛出了一个异常,但是尽管堆栈中存在一个语法正确的 try-catch块,但它既没有得到处理(在这种情况下应该发出一条消息),也没有进程崩溃。从调试日志中,我可以看到相关线程卡住了,尽管其余线程继续运行。
我已经阅读了堆栈展开文档,并且在某处我看到函数的参数也被认为是自动变量,并在展开过程中被破坏。这让我想到了一个问题:当我将this的 const 引用(其中有一个相应的catch块)传递给抛出异常的方法时会发生什么?是否有可能 ref 破坏了调用者对象,并且即使堆栈展开已经开始,catch 块现在也无法访问?
让我添加一些伪代码:
提前致谢...
编辑:好的,尝试生成一个可执行代码以供参考,我相信我几乎回答了我自己的问题。
这是代码:
输出是:
这意味着*this
参数不会在unwaryFunction
. 我可能在实际代码中还有其他一些错误(因为类似于“异常捕获...”的消息没有被打印出来)。我会保留这个问题以供将来参考。总之谢谢你的关心。
swift - 无论您来自哪里,如何有条件地修改 UINavigationController 的后台堆栈以跳过以前的条目?
我们试图弄清楚当向后导航时如何有条件地排除我们的后台堆栈中的某些屏幕。例如,采取以下屏幕:
- 主仪表板(您可以从这里转到 2 或 3)
- 订单管理(您可以从这里转到 3 或 6)
- 输入订单
- 查看订单
- 订单确认(如果您在此处完成,则后面应跳过 3 和 4)
- 订单状态(如果您在此处完成,则返回应跳过 5(它已经跳过 3 和 4))
屏幕 3-5 代表输入订单,因此如果您已进入确认页面,我们不希望您返回查看或编辑页面。
出于同样的原因,如果您从确认页面导航到“订单状态”,我们不希望您导航回“订单确认”,而是返回“订单管理”或“主仪表板”(取决于关于你是如何到达那里的)
注意:我们知道 popToViewController 以及它如何让您跳过您所在位置和您指定的控制器之间的所有控制器。问题是我不知道那个视图控制器是什么。我只知道我想跳过哪个(如果它们存在的话)。更重要的是,后退按钮反映了堆栈中的内容,而不是我要弹出的内容。这就是为什么我希望告诉系统“返回时忽略堆栈中的这些”。希望这是有道理的。
我的粗略尝试是像这样修改后堆栈...
注意:这是简化的代码。我们实际上并没有挂在视图控制器的实例上。我们通过在后台堆栈中查找它们的类型来找到索引。这仅用于简单说明目的。
当导航工作时,在动画期间,后退按钮显示原始后退位置,然后在动画之后,标签的值“捕捉”以显示新的后退位置。这当然证明这不是正确的方法。
我知道有放松的segues,但这担心你要去哪里。我们只想在导航离开后从积压中删除项目,否则保持后台堆栈完好无损。
那么如何实现这种忽略先前步骤的行为呢?
c++ - 有没有办法让 DisableUserModeCallbackFilter 在 Windows 10 中工作?
有没有办法让DisableUserModeCallbackFilter
(或类似的)在 Windows 10 上工作?
它应该允许从用户模式代码引发的异常跨用户/内核边界传播,并且它在 Windows 7 之前的早期 Windows 版本上有一个修补程序,但我似乎无法让它在最近的版本上运行版本。
这是一个在 Windows 10 x64 上似乎出错的测试程序,但在 Windows XP x86 上却没有:
exception - 一些调用会导致堆栈展开,但不会引发 C++ 异常
我使用 Visual Studio Native Unit Test Framework for C++。当断言失败时,不会执行下一个语句并调用本地对象析构函数,因此似乎引发了异常,但我无法通过catch (...)
子句捕获任何 C++ 异常。经过一些实验,我注意到__int2c()
调用(触发 2c 中断,由于文档),例如,具有相同的效果。到今天为止,我只知道具有这种行为的异常。您能否给我一些提示,说明在这种情况下可能是什么原因?
更新:
这是一个代码示例
x86-64 - 打破 ELF/Linux 上的堆栈/调用帧信息链?
我正在尝试做一件相当利基的事情,它本质上是破坏CFI
(DWARF EH 信息中的调用帧信息)和rbp
帧rsp
之间的链接。主要原因是,在线程控制流的某个点之后,我想做一个调用延续,这基本上是一个单向尾调用与一个应该清理堆栈然后返回到堆栈顶部的 yield准备在延续点再次执行。
这是原则上的想法,只要我将与堆栈混淆的行注释掉,它就可以工作:
我知道 SP/BP 寄存器背后的一般原则,我专门使用-fno-omit-frame-pointer
. 我的问题是,在花了几个小时试图让它工作之后,我错过了什么?似乎对堆栈布局的任何更改,即使像在调用前推送并保持对齐一样简单,都会导致从类似这样的事情开始的雪球崩溃(自定义信号处理程序):
有问题的 ABI 是libc++
/libc++abi
在x86_64
Linux 上,具有基于 LLVM/Clang 6.0.X 的工具链。我几乎尝试了所有方法,我知道上面看起来很奇怪,但它是内联汇编的 MS 扩展,我在反汇编中多次检查它会生成完全正常的代码。据我了解,这是 CFI 和基于帧指针的东西之间的一些奇怪的冲突,但我并不是那么擅长,x86_64
所以我不确定我错过了什么。我知道展开过程是由哨兵(最后一帧上的空 SP/FP)终止的,但此时我真的迷路了,因为即使调试器也被完全抛弃了。
如果有人有任何非常感谢的建议,我尝试了各种方法,但核心问题是相同的,一旦我触摸堆栈,即使我将其恢复正常,一切都会变得混乱。超出 asm 块的破坏并不重要,因为最后一次调用通常不意味着返回。我确实注意到的一件事是,这似乎与 TLV 有某种关系,但我不确定 NPTL 是如何配置的。
任何帮助或建议我都会非常感激。
编辑:
看起来 Valgrind 的这条评论可以解释正在发生的事情:
c++ - 展开回溯跟踪如何在内部工作?
这个问题只是为了理解目的。
_Unwind_Backtrace 在内部做什么来跟踪调用的函数调用堆栈。
每次我们调用一个函数来跟踪堆栈时,一些展开库代码是否会在内部执行?
还是只有当我们调用 _Unwind_Backtrace 时,它才会收集函数堆栈并给出信息?如果是这样,它如何收集信息。
我已经用谷歌搜索了一段时间,但找不到任何关于展开器如何工作的信息。如果有人知道,请解释一下。