Перевыпуск в objc ARC с -O, но не с -O0

Я уже подал радар (rdar://12311693, http://openradar.appspot.com/12311693) для следующей проблемы, но я думал, d, чтобы узнать, может ли кто-нибудь обнаружить ошибку в моем коде, которая может привести к сбою.

Следующий пример кода приводит к сбою из-за чрезмерного выпуска при построении с включенной оптимизацией компилятора (-Os), но не сбой при отключении оптимизации компилятора (-O0). Проект строится с помощью Xcode 4.4.1 (4F1003), компилятора Apple LLVM 4.0

Приложение сбой, когда num2 перевыполнен. Включите объекты Zombie, чтобы подтвердить, что это так.

// This crashes under -Os, but not under -O0
NSNumber *num1 = @((float)arc4random() / (float)UINT32_MAX);
NSNumber *num2 = @((float)arc4random() / (float)UINT32_MAX);

NSNumber *foo1 = num1;
NSNumber *foo2 = num2;

for (NSUInteger i=0; i<2; i++) {

    NSLog(@"foo1: %p %@", foo1, foo1);
    NSLog(@"foo2: %p %@", foo2, foo2);

    // swap foo1 and foo2
    foo1 = num2;
    foo2 = num1;
}

Ответ 1

Ошибка компилятора. Спасибо, что зарегистрировали его.

num1 и num2 должны гарантировать срок службы указанных объектов. Я подозреваю, что оптимизатор [правильно] повторно использует слоты стека и [неправильно] испускает последовательность release/сохранения, что приводит к этой проблеме.


В ответ на stackmaster; это ошибка компилятора. Весь смысл ARC заключается в том, чтобы перейти Objective-C к точке, где компилятор может проанализировать код со 100% уверенностью, чтобы знать, где хранить записи/релизы, которые вам, разработчику, не нужно. По большому счету, он может достичь именно этого, даже перед лицом потоковой передачи, до тех пор, пока оба кода, которые используют объект в мире MRR, хорошо себя ведут, и разработчик не "убегает" от объекта из управления ARC и сделать что-то непослушное. Два больших ifs, но значительное улучшение по сравнению с MRR.

Наконец, если ваш код не работает при оптимизации (когда ошибки компилятора не вступают в игру) , это потому, что ваш код поврежден. Правильно написанный оптимизатор не сломает правильно написанный код.

В то время как некоторые компиляторы, как известно, ошибочны, LLVM не является одним из них (я не буду претендовать на GCC, потому что я не использовал его в течение многих лет, но я бы сказал, что то же самое можно сказать). Система iOS или OS X выполнит миллионы и миллионы строк скомпилированного кода с оптимизированной поддержкой при каждой загрузке, и система работает достаточно хорошо.

Итак, нет, "оптимизатор включен" никогда не является окончательным разрешением для сбоя.


Как отметил Catfish_man, есть варианты эзотерического оптимизатора, которые специально создадут технически неправильный код. Они не поддерживаются -O или другими "стандартными" оптимизациями. Они в основном сосредоточены на математических упражнениях и, таким образом, обычно не будут приводить к сбоям, а не быстрее ползучести ошибки в вычислениях.