Какой надежный способ вызвать сбой приложения iOS?

136

Я хочу проверить отчеты о сбоях моего приложения в полевых условиях, преднамеренно заставляя его падать, когда пользователь выполняет определенное действие, которое реальный пользователь вряд ли случайно сделает.

Но какой хороший надежный способ вызвать сбой приложения, который не создает предупреждение во время компиляции?

Изменить: Обратите внимание, что многие, казалось бы, очевидные ответы на этот вопрос приводят к исключениям, которые попадают в Какао и, следовательно, не приводит к падению приложения.

Нестор
источник
WebKit discarded an uncaught exceptionПока я получаю все эти идеи! Кто знал, что в эти дни было так сложно вывести приложение из строя?
Нестор
Я не думаю, что что-то из этого имеет какое-либо отношение к WebKit ...
BoltClock
23
Да, откройте Safari на iPad 1 и перейдите на страницу с большим количеством изображений. У меня всегда работает. : /
Алан Б
4
(void)0/0;,(void)*(char*)0;
Кевин
1
Будьте осторожны с некоторыми ответами, вызывающими неопределенное поведение . Это на самом деле очень неприятный совет!
USR

Ответы:

140

в Objective-C используйте C напрямую, чтобы вызвать плохой доступ

strcpy(0, "bla");

Примечание: хотя это работает на любой системе, которую я знаю - в будущей версии среды выполнения C ИЛИ компиляторе это может больше не привести к сбою. см. Является ли разыменование нулевого указателя неопределенным поведением в Objective-C? )

(в быстром вы должны были бы соединиться с objC, чтобы сделать это)

DAij-Джан
источник
это ИМХО самый надежный способ
Михал Крефт
Ах да, это WebKit discarded an uncaught exceptionтоже помогает обойтись.
Нестор
была еще опечатка: D нет @ "бла", но "бла"
Daij-Djan
4
Очевидно ( stackoverflow.com/questions/13651642/… ), это неопределенное поведение и на самом деле очень плохой ответ! Компилятор может юридически оптимизировать оба оператора и ничего не делать. Я предлагаю вам удалить этот ответ. Это может привести людей к этому.
USR
3
на ios, osx, windows и redhat он всегда ломался, поэтому в данном контексте я бы сказал, что он действителен. Я добавлю отказ от ответственности
Daij-Djan
97

Мой текущий любимый:

assert(! "crashing on purpose to test <insert your reason here>");

Классика:

kill( getpid(), SIGABRT );

И некоторые pr0n:

*(long*)0 = 0xB16B00B5;

Все они генерируют сбои, захваченные моим инструментом отчетности о сбоях.

djromero
источник
14
assert не падает на
релизных
6
это зависит от ваших настроек сборки; Кроме того, я думаю, что вопрос о тестировании, кажется, нормально держать утверждения в тестовых сборках
djromero
3
Многие люди (включая меня) оставляют утверждения в сборках релизов. Нет причин отключать их.
Султан
5
@Sulthan: assert()это функция отладки, которая не имеет смысла оставлять такие ошибки в сборках релизов. Для этого есть юнит-тесты.
MestreLion
18
ИМХО assertэто не функция отладки. Неудачное утверждение - это ошибка, которую вы считаете невозможной. Лучше прервать даже сборку релиза, чем продолжать запускать программу с непредсказуемыми последствиями.
djromero
27

Поскольку мы все используем Clang для iOS, это довольно надежно:

__builtin_trap();

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

Дитрих Эпп
источник
22

Как насчет старого доброго переполнения стека :)

- (void)stackOverflow
{
    [self stackOverflow];
}
Taum
источник
16

Самый популярный - нераспознанный сбой селектора:

NSObject *object = [[NSObject alloc] init];
[object performSelector:@selector(asfd)];

Убедитесь, что в этом классе не реализован метод -asdf

Или индекс за пределами исключения:

NSArray * array = [NSArray array];
[array objectAtIndex:5];

И конечно kill( getpid(), SIGABRT );

wirrwarr
источник
12

Я думаю, что в Свифте вы можете легко бросить роковую ошибку:

func foo() {
    fatalError("crash!")
}

На самом деле она даже предназначена для использования этой функции на случай, если что-то пойдет не так, чтобы приложение зависало.

Чтобы избежать оператора if в особом случае, вы также можете использовать precondition. Это похоже на assert, делает, таким образом, намерение (если требуется ) довольно ясным и не удаляется в финальной версии как assert. Это используется как precondition(myBoolean, "This is a helpful error message for debugging.").

borchero
источник
9

Отправить сообщение освобожденному объекту

Андрей Чернуха
источник
34
Это на самом деле очень ненадежно. Вы по-прежнему можете отправлять сообщения освобожденным объектам, если их память не используется повторно. Это единственная причина, по которой людям исторически было очень трудно отлаживать ошибки двойного выпуска. Только когда память освобождается другим объектом, отправка сообщения может вызвать исключение.
Майк Веллер
7
exit(0);

(должен ... ввести ... 30 символов)

Стив Роджерс
источник
Спасибо за возражения, но на самом деле это заставит приложение завершиться и вернуться к Springboard, что, хотя и может быть полезно само по себе, не то, что хотел OP, то есть вызвать неисследованное исключение
Стив Роджерс
6

Вы также можете вызвать исключение:

[NSException raise:NSInternalInconsistencyException
            format:@"I want to test app crashes!."];
Алессандро Вендрусколо
источник
2
Я не думаю, что исключение - это хороший способ, ловля исключения является обычной, так что вы можете случайно ее поймать. Ловить сигналы не так часто, поэтому плохой доступ или подобные вещи будут более надежными. :)
Михал Крефт
3

Добавьте распознаватель жестов в представление, которое распознает касание 10 пальцами (5 пальцев для iPhone при 10 могут быть немного переполнены). К GR прикреплен метод, который выполняет любой из ранее упомянутых безошибочных способов заставить ваше приложение аварийно завершиться. Большинство пользователей не собираются прилагать 10 усилий к вашему приложению, поэтому вы в безопасности от обычного пользователя, случайно вызвавшего сбой.

Однако вы должны иметь возможность использовать что-то вроде Testflight или просто развернуть его на персональных устройствах и протестировать на свободе, прежде чем отправлять его в Apple. В случае принудительного сбоя Apple может отклонить ваше приложение.

jhelzer
источник
Мое приложение Cocos2d падает, когда я выполняю экстремальное мультитач, и я вижу это как неразрешенную ошибку. У меня нет GR, но я включил мультитач в Cocos2d. Я испытываю аварию, которую вы описываете? Вы имеете в виду, что это ожидаемое / желаемое поведение?
Фредрик Йоханссон
@Fredrik Я не думаю, что вы ожидаете сбой, который вы описываете (ожидаются сбои в IMO, и лично я не думаю, что это хорошая идея, чтобы целенаправленно добавлять их в ваше приложение). Вы можете попытаться символизировать сбой и выяснить, какой именно метод вызывает сбой приложения. Это может быть что-то внутри фреймворка Cocos2d, вызывающее сбой при возникновении «экстремального мультитач». Если это так, то лучше всего подавать ошибку с парнями из Cocos2d.
Джелзер
2

может попробовать что-то вроде

NSArray* crashingArray = [NSArray arrayWithCapacity:1];
[crashingArray release];

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

Saliom
источник
3
Не компилируется с включенным ARC.
Викингосегунд
хорошо, если вы используете ARC, вы также можете сделать это: NSArray * crashingArray = [NSArray arrayWithCapacity: 1]; [crashingArray objectAtIndex: 0]; это должно быть сбой
Салиом
1

Я пойду с:int raise(int sig);

Чтобы получить больше информации >man raise

Витаутас
источник
0

Я бы просто убил процесс нормально:

kill(getpid(), SIGKILL);

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

Рами Аль Зухури
источник
это уже включено в ответ
madmw
0

я использую

[self doesNotRecognizeSelector:_cmd]; 
Duyen-Хоа
источник
2
Это сообщение автоматически помечается как низкое качество, потому что это всего лишь код. Не могли бы вы расширить его, добавив текст, объясняющий, почему это решает проблему?
gung - Восстановить Монику
0

При работе с RubyMotion я использую это:

    n=Pointer.new ('c', 1)
    n[1000] ='h'
Раймонд
источник
0

Попробуй это:

- (IBAction)Button:(id)sender
{
    NSArray *array = [NSArray new];
    NSLog(@"%@",[array objectAtIndex:8]);
}
Раджеш Логанатхан
источник
-1

неправильное NSLogутверждение сделает это

NSLog(@"%@",1);
Mutawe
источник