Ответ 1
Я пробовал этот код, и он действительно умирает с незаконной инструкцией. Так что я сделал рытье и обнаружил, что он умирает в _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, который является инструкцией по даффу, помещенной туда, чтобы он сработал, если bge.n
не заставляет нас перепрыгивать через него.
Причина, по которой это происходит, состоит в том, что r0
должен быть меньше r1
. r0
и r1
загружаются из памяти в r4 + 32
, которая вернулась в стек, чтобы понять это. Я думаю, что r4
есть aSemaphore
в примере кода, т.е. предмет, переданный в dispatch_semaphore_release
. + 32
означает, что он считывает 32 байта в структуру, на которую указывает aSemaphore
(это указатель на структуру dispatch_semaphore_s
). Таким образом, общее, что он делает, читает 4 байта из aSemaphore + 32
и помещает их в r0
и читает 4 байта из aSemaphore + 36
и помещает их в r1
.
Затем сравнение эффективно сравнивает значение aSemaphore + 32
и aSemaphore + 36
. Чтение того, что dispatch_semaphore_create
я могу видеть, что он сохраняет значение, переданное как для aSemaphore + 32
, так и aSemaphore + 36
. Я также обнаружил, что dispatch_semaphore_wait
и dispatch_semaphore_signal
коснитесь значения в aSemaphore + 32
, чтобы увеличить и уменьшить его. Это означает, что причина его разлома заключается в том, что текущее значение семафора меньше значения, переданного в dispatch_semaphore_create
. Таким образом, вы не можете распоряжаться семафором, когда текущее значение меньше значения, которое было создано с помощью.
Если вы читали здесь и понимали мои промахи, то хорошо сделали! Надеюсь, это поможет!
UPDATE:
Вероятно, лучше посмотреть на источник (указанный JustSid) здесь - http://opensource.apple.com/source/libdispatch/libdispatch-187.7/src/semaphore.c - глядя на функцию _dispatch_semaphore_dispose
, которую мы видим:
if (dsema->dsema_value < dsema->dsema_orig) {
DISPATCH_CLIENT_CRASH("Semaphore/group object deallocated while in use");
}
Итак, да, вот и все, вот почему он падает!