iOS版本中的非法操作码

时间:2016-07-10 21:09:04

标签: c++ ios boost arm stdatomic

以下代码(从大型项目中最小化)在使用XCode 7.3.1构建时导致EXC_BAD_INSTRUCTION崩溃,iOS版为Boost 1.61:

#0  0x0000000100047a78 in std::__1::__atomic_base<boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>, false>::store(boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>, std::__1::memory_order) [inlined] at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/atomic:842
#1  0x0000000100047a74 in boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::deallocate_impl_unsafe(boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node*) at /Users/deinzer/src/pipeline.ios/boost/boost/lockfree/detail/freelist.hpp:251
#2  0x00000001000479e8 in boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_stack<std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >(std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> const&, unsigned long) at /Users/deinzer/src/pipeline.ios/boost/boost/lockfree/detail/freelist.hpp:64
#3  0x00000001000478e0 in boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::queue(unsigned long) at /Users/deinzer/src/pipeline.ios/boost/boost/lockfree/queue.hpp:205
#4  0x0000000100047840 in main at /Users/deinzer/src/iostester/lockfreecrash/lockfree_crash/lockfree_crash/main.mm:7
#5  0x00000001821d68b8 in start ()

stacktrace似乎告诉我,问题来自c ++原子操作:

0x100047a5c <+72>:  mov    x20, x0
0x100047a60 <+76>:  add    x0, sp, #16               ; =16 
0x100047a64 <+80>:  bl     0x100047aac               ; boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>::get_ptr at tagged_ptr_dcas.hpp:78
0x100047a68 <+84>:  mov    x1, x0
0x100047a6c <+88>:  mov    x0, x20
0x100047a70 <+92>:  bl     0x100047aa4               ; boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>::set_ptr at tagged_ptr_dcas.hpp:83
0x100047a74 <+96>:  ldp    x9, x8, [sp]
->  0x100047a78 <+100>: .long  0xc87f7e7f                ; unknown opcode
0x100047a7c <+104>: stxp   w10, x9, x8, [x19]
0x100047a80 <+108>: cbnz   w10, 0x100047a78          ; <+100> [inlined] std::__1::__atomic_base<boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>, false>::store(boost::lockfree::detail::tagged_ptr<boost::lockfree::detail::freelist_stack<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node, std::__1::allocator<boost::lockfree::queue<int*, boost::parameter::void_, boost::parameter::void_, boost::parameter::void_>::node> >::freelist_node>, std::__1::memory_order) + 4 at freelist.hpp:251

反汇编输出显示非法操作码:

a

问题只发生在

  • 启用优化(O1,O2和O3)
  • 目标架构设置为arm64

代码运行正常,如果

  • 优化已关闭(O0)
  • 目标架构设置为armv7

我想知道问题的根本原因。这是一个clang问题,一个std :: atomic或boost bug?可以做些什么来避免这个问题?

1 个答案:

答案 0 :(得分:5)

您的反汇编程序拒绝确认的指令是ldxp xzr, xzr, [x19] - 换句话说,是一个加载来填充独占监视器,以便存储独占将成功(或失败并重新启动,如果确实有一些并发内存访问,所以可以保证商店的原子性)。由于这是在这种情况下唯一重要的方面,即我们并不关心加载的实际数据,因此我们不知不觉地使用零寄存器作为目标来简单地丢弃数据并避免分配临时寄存器以加载到。

这里的问题是,使用相同的寄存器加载对的两个目标在架构上是不可预测的。这必须是Boost或Clang中的错误,具体取决于违规指令是来自某些显式汇编代码还是来自编译器内部实现。通过取消这些模板,我认为它在std :: atomic中,但是因为我的知识在C ++ 98之后停止了,我不确定指向哪个指针。< / p>

引用the ARMv8 ARM不可预测行为附录的ldxp部分:

  

如果t == t2,则必须执行以下行为之一:

     
      
  • 说明未完成。
  •   
  • 指令以NOP
  • 执行   
  • 指令使用指定的寻址模式执行加载,基址寄存器[sic]设置为UNKNOWN值。
  •   

很可能在设计人员选择第三个选项的某些CPU上,这段代码最终会按预期运行(实际上可以进行测试)。然而,Apple的CPU设计人员似乎已经采用了第一个选项,至少他们的核心位于相关设备中,因此爆炸。

__atomic_base::store()实现的内容应该能够做到整齐地修复它只是重复使用为商店独占状态而不是xzr s之一分配的临时寄存器,例如这个例子是ldxp xzr, x10, [x19]。这应该使指令定义良好而不影响任何其他代码(以下stxp将始终无条件地覆盖整个寄存器),并且不需要优化器分配额外的寄存器。可以想象,可以编写一个工具来对已编译的二进制文件进行后处理,扫描相关的指令对,从而修复加载操作数,但是只需提交相应的错误报告并将其修复为来源 - 事实证明,我怀疑的基础优化问题是has been reported against upstream LLVM already