c++ - EXC_BREAKPOINT 崩溃的原因

标签 c++ macos debugging

我在 Logic X 内运行的 C++ 音频单元组件中的某些用户计算机上发生了崩溃。不幸的是,我无法在本地重复它,在尝试弄清楚它如何发生的过程中,我遇到了一些问题问题。

以下是故障转储中的相关信息:

Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY

Termination Signal: Trace/BPT trap: 5
Termination Reason: Namespace SIGNAL, Code 0x5
Terminating Process: exc handler [0]

问题是:

  • 在我正在查看的情况下,什么可能会导致 EXC_BREAKPOINT。 Apple 提供的此信息是否完整且准确:“与异常退出类似,此异常旨在为附加的调试器提供在执行过程中的特定点中断进程的机会。您可以从自己的异常中触发此异常使用 __builtin_trap() 函数的代码。如果没有附加调试器,则进程将终止并生成崩溃报告。”
  • 为什么它会发生在 SharedObject + 200 上(参见反汇编)
  • RBX 是崩溃发生时的“this”指针吗?

崩溃发生在这里:

juce::ValueTree::SharedObject::SharedObject(juce::ValueTree::SharedObject const&) + 200

C++如下:

SharedObject (const SharedObject& other)
    : ReferenceCountedObject(),
      type (other.type), properties (other.properties), parent (nullptr)
{
    for (int i = 0; i < other.children.size(); ++i)
    {
        SharedObject* const child = new SharedObject (*other.children.getObjectPointerUnchecked(i));
        child->parent = this;
        children.add (child);
    }
}

反汇编:

->  0x127167950 <+0>:   pushq  %rbp
    0x127167951 <+1>:   movq   %rsp, %rbp
    0x127167954 <+4>:   pushq  %r15
    0x127167956 <+6>:   pushq  %r14
    0x127167958 <+8>:   pushq  %r13
    0x12716795a <+10>:  pushq  %r12
    0x12716795c <+12>:  pushq  %rbx
    0x12716795d <+13>:  subq   $0x18, %rsp
    0x127167961 <+17>:  movq   %rsi, %r12
    0x127167964 <+20>:  movq   %rdi, %rbx
    0x127167967 <+23>:  leaq   0x589692(%rip), %rax      ; vtable for juce::ReferenceCountedObject + 16
    0x12716796e <+30>:  movq   %rax, (%rbx)
    0x127167971 <+33>:  movl   $0x0, 0x8(%rbx)
    0x127167978 <+40>:  leaq   0x599fe9(%rip), %rax      ; vtable for juce::ValueTree::SharedObject + 16
    0x12716797f <+47>:  movq   %rax, (%rbx)
    0x127167982 <+50>:  leaq   0x10(%rbx), %rdi
    0x127167986 <+54>:  movq   %rdi, -0x30(%rbp)
    0x12716798a <+58>:  leaq   0x10(%r12), %rsi
    0x12716798f <+63>:  callq  0x12711cf70               ; juce::Identifier::Identifier(juce::Identifier const&)
    0x127167994 <+68>:  leaq   0x18(%rbx), %rdi
    0x127167998 <+72>:  movq   %rdi, -0x38(%rbp)
    0x12716799c <+76>:  leaq   0x18(%r12), %rsi
    0x1271679a1 <+81>:  callq  0x12711c7b0               ; juce::NamedValueSet::NamedValueSet(juce::NamedValueSet const&)
    0x1271679a6 <+86>:  movq   $0x0, 0x30(%rbx)
    0x1271679ae <+94>:  movl   $0x0, 0x38(%rbx)
    0x1271679b5 <+101>: movl   $0x0, 0x40(%rbx)
    0x1271679bc <+108>: movq   $0x0, 0x48(%rbx)
    0x1271679c4 <+116>: movl   $0x0, 0x50(%rbx)
    0x1271679cb <+123>: movl   $0x0, 0x58(%rbx)
    0x1271679d2 <+130>: movq   $0x0, 0x60(%rbx)
    0x1271679da <+138>: cmpl   $0x0, 0x40(%r12)
    0x1271679e0 <+144>: jle    0x127167aa2               ; <+338>
    0x1271679e6 <+150>: xorl   %r14d, %r14d
    0x1271679e9 <+153>: nopl   (%rax)
    0x1271679f0 <+160>: movl   $0x68, %edi
    0x1271679f5 <+165>: callq  0x12728c232               ; symbol stub for: operator new(unsigned long)
    0x1271679fa <+170>: movq   %rax, %r13
    0x1271679fd <+173>: movq   0x30(%r12), %rax
    0x127167a02 <+178>: movq   (%rax,%r14,8), %rsi
    0x127167a06 <+182>: movq   %r13, %rdi
    0x127167a09 <+185>: callq  0x127167950               ; <+0>
    0x127167a0e <+190>: movq   %rbx, 0x60(%r13)        // MY NOTES: child->parent = this
    0x127167a12 <+194>: movl   0x38(%rbx), %ecx
    0x127167a15 <+197>: movl   0x40(%rbx), %eax
    0x127167a18 <+200>: cmpl   %eax, %ecx

更新1: 看起来 RIP 表明我们正处于“add”调用的中间,即这个函数,内联:

/** Appends a new object to the end of the array.

    This will increase the new object's reference count.

    @param newObject       the new object to add to the array
    @see set, insert, addIfNotAlreadyThere, addSorted, addArray
*/
ObjectClass* add (ObjectClass* const newObject) noexcept
{
    data.ensureAllocatedSize (numUsed + 1);
    jassert (data.elements != nullptr);
    data.elements [numUsed++] = newObject;

    if (newObject != nullptr)
        newObject->incReferenceCount();

    return newObject;
}

更新2: 崩溃时相关寄存器的寄存器值:

this == rbx: 0x00007fe5bc37c950
&other == r12: 0x00007fe5bc348cc0
rax = 0
rcx = 0

最佳答案

我怀疑问题在于,一个本应放置在堆上的共享的、引用计数的对象被无意中分配到了堆栈上。如果堆栈展开并随后被覆盖,并且对引用计数对象的引用仍然存在,那么当访问该引用时,将在不可预测的时间发生随机事件。 ( this 和 &other 的地址空间的接近性也让我怀疑它们都在堆栈上。)

关于c++ - EXC_BREAKPOINT 崩溃的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48849479/

相关文章:

ruby-on-rails - rails 不在调试器处停止的原因

swift - 如何使用 ICDeviceBrowser - 找不到相机

linux - 如何通过 CLI 快速重命名 macOS 或 Linux 上的文件?

macos - dnsmasq 和多个地址

iOS 应用程序因启动时崩溃而被拒绝(无法重现)

c++ - QFile读取超时

c++ - 调用 `libcurl` 和 `curl_easy_send` 时应用哪些 `curl_easy_recv` 选项?

c# - 输出发送到打印机

c++ - 如果具有相同的名称,则返回列表元素的指针

java - 在eclipse中调试Jar文件