Объект, созданный внутри области, освобожденный даже при использовании вне области видимости
Обновление: Это было исправлено в iOS 6.1 DP3 SDK.
Я выследил сбой при использовании после ARC, используя конфигурацию сборки по умолчанию (отладка, похоже, работает нормально). Проблема возникает при создании объекта внутри if-scope с непостоянным условием, присваивая его переменной извне области, а затем ссылается только на переменную с помощью массива Objective-C или словарных литералов.
Вот самый маленький воспроизводимый случай, который мне удалось найти:
void test(BOOL arg)
{
id obj = nil;
if (arg) {
obj = [NSObject new];
}
// obj already deallocated here
@[obj];
// but using NSArray works
//[NSArray arrayWithObject:obj];
// @[obj] works if obj is referenced i.e. by NSLog print out
//NSLog(@"%@", obj);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
test(YES);
}
return 0;
}
Когда я создаю и запускаю это с включенными объектами зомби, я получаю это сообщение об ошибке:
-[NSObject retain]: message sent to deallocated instance 0x100109100
Как я прокомментировал в коде, он отлично работает, если obj
ссылается каким-то другим способом, например, с помощью NSLog
или с помощью NSArray
. Я неправильно понял, как объекты выпущены с ARC и областями или это ошибка оптимизации в LLVM или Clang?
Я использую Xcode 4.5.2 с clang версии 4.1 (теги/Apple/clang-421.11.66) (на основе LLVM 3.1svn). Я могу воспроизвести его при создании для 64-разрядного x86 для iOS-симулятора и Mac OS X, и я уверен, что такая же проблема возникает при создании ARM, поскольку проблема была впервые обнаружена при запуске выпуска на iPhone.
Я опубликовал отчет об ошибке Apple и создал открытый радарный отчет.
Что, если что-нибудь, мне не хватает?
Обновить, сделал еще несколько экспериментов:
Как сказал Габро, компилятор переводит @[]
в оператор [NSArray arrayWithObjects:count:]
, поэтому я сделал несколько тестов:
// works
id a[] = {obj};
[NSArray arrayWithObjects:a count:1];
// does not work
const id *b = (id[]){obj};
[NSArray arrayWithObjects:b count:1];
// does not work
[NSArray arrayWithObjects:(id[]){obj} count:1];
Итак, я предполагаю, что это происходит при объединении ARC и анонимных массивов C.
Ответы
Ответ 1
Я только что протестировал следующий код как для OSX (x86 64), так и для iOS Simulator, и я не могу воспроизвести ошибку
void test(BOOL arg) {
id obj = nil;
if (arg) {
obj = [NSObject new];
}
@[obj];
NSLog(@"Hi there");
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
test(YES);
}
return 0;
}
Вышеприведенный код просто печатает Hi there
в консоли и возвращает.
Моя конфигурация такая же: XCode 4.5.2 и Apple clang версии 4.1 (теги/Apple/clang-421.11.66) (на основе LLVM 3.1svn) в качестве компилятора.
ИЗМЕНИТЬ
Я также попытался скомпилировать из командной строки (после добавления #include <Foundation/Foundation.h>
в начале вышеприведенного примера) с помощью
clang -fobjc-arc -framework Foundation main.m
И результат снова был
2012-12-03 12:47:45.647 a.out[39421:707] Hi there
РЕДАКТИРОВАТЬ 2
Как указано в комментариях, можно воспроизвести ошибку, повышающую уровень оптимизации над -O0
. Подведение итогов:
clang -O0 -fobjc-arc -framework Foundation main.m
программа работает как ожидалось
clang -O1 -fobjc-arc -framework Foundation main.m
появляется ошибка, представленная в вопросе. Это верно при любом уровне оптимизации над -O0
Это определенно ошибка в компиляторе.
Ответ 2
Вы ничего не пропустили. Это ошибка компилятора.