为什么此代码会导致“EXC_BAD_INSTRUCTION”?

时间:2011-11-27 17:49:55

标签: iphone ios grand-central-dispatch

dispatch_semaphore_t aSemaphore = dispatch_semaphore_create(1);        
dispatch_semaphore_wait(aSemaphore, DISPATCH_TIME_FOREVER);
dispatch_release(aSemaphore);

当程序运行到 dispatch_release(aSemaphore)时,会导致“EXC_BAD_INSTRUCTION”,然后崩溃。为什么呢?

3 个答案:

答案 0 :(得分:40)

我尝试了这段代码,确实因非法指令而死亡。所以我做了一些挖掘,发现它在_dispatch_semaphore_dispose中死亡。那么让我们来看看它是什么(ARMv7在这里,因为它很容易理解!):

__dispatch_semaphore_dispose:
000040a0            b590        push    {r4, r7, lr}
000040a2            4604        mov     r4, r0
000040a4            af01        add     r7, sp, #4
000040a6        e9d40108        ldrd    r0, r1, [r4, #32]
000040aa            4288        cmp     r0, r1
000040ac            da00        bge.n   0x40b0
000040ae            defe        trap
...

它死在0x40ae,这是一个duff指令放在那里,如果bge.n没有让我们分支跳过它就会崩溃。

失败的原因是因为r0必须小于r1r0r1已从r4 + 32的内存中加载,该内存已经回到堆栈中以便计算出来我认为 r4是{{ 1}}在示例代码中,即传递给aSemaphore的东西。 dispatch_semaphore_release表示它正在读取+ 32指向的结构中的32个字节(它是指向aSemaphore结构的指针)。总的来说,它正在从dispatch_semaphore_s读取4个字节并将它们放入aSemaphore + 32并从r0读取4个字节并将它们放入aSemaphore + 36

然后比较有效地比较r1aSemaphore + 32的值。阅读aSemaphore + 36我可以看到它存储传递给dispatch_semaphore_createaSemaphore + 32的值的内容。我还发现aSemaphore + 36dispatch_semaphore_wait触及dispatch_semaphore_signal处的值,以递增和递减它。这意味着它被破坏的原因是因为信号量的当前值小于传递给aSemaphore + 32的值。所以当当前值小于它创建的值时,你不能处理信号量。

如果你读到这里并理解我的随意,那么做得好!希望它有所帮助!

<强>更新

最好在这里查看源代码(JustSid指出) - http://opensource.apple.com/source/libdispatch/libdispatch-187.7/src/semaphore.c - 查看我们看到的dispatch_semaphore_create函数:

_dispatch_semaphore_dispose

所以,是的,你去了,这就是崩溃的原因!

答案 1 :(得分:17)

更简洁的答案:您正在使用错误的值创建信号量,它应该为零。使用值1创建它意味着您稍后释放仍然“正在使用”的信号量,并且GCD故意生成非法指令,以帮助您调试您拥有更多服务员信号量的事实。

答案 2 :(得分:1)

你可以创建一个零值的信号量,但我相信它只会毫无用处。我在一个类中有一个信号量字段,导致它在去初始化时崩溃。这是我修复它的方法(Swift代码):

deinit {
  while (dispatch_semaphore_signal(semaphore) != 0) {}
}

一个相当尴尬的补丁,但它有效!