如何快速让iOS应用程序崩溃?

57

我想测试一下我的崩溃分析。我没有意识到有意让应用程序崩溃是多么困难的事情。在编程过程中,看起来很简单。是否有人有建议可以强制我的应用程序崩溃?我不是指"内存错误"这种小型崩溃,而是手机不知道该怎么办。我需要它至少作为崩溃进入设备日志,在Xcode的组织者中显示。有什么建议吗?


2
只是访问数组范围之外的项... - T. Benjamin Larsen
58
坚持编程,最终会有所成就 :) - Clint Warner
我尝试访问数组范围之外的项,但没有成功。只是将其视为null。当我尝试用该值除以其他数时,它就将其视为0。由于这是ARM架构,实际上它会除以零并继续运行。 - Katushai
3
真的吗?NSArray *array = @[@1, @2]; NSNumber *number = [array objectAtIndex:2];不会崩溃吗? - T. Benjamin Larsen
你搞定了,那个崩溃了。应该把它提交为答案。我没有深入研究这个错误。 - Katushai
9个回答

93
@throw NSInternalInconsistencyException;

这个可以工作。我接受了这个答案,因为它先到达,但assert(no)也可以工作。此外,我选择这个答案是因为它似乎是原生的Cocoa而不是C,所以苹果为这个特定的原因设计了它(我猜)。 - Katushai
4
抛出异常不一定导致崩溃。如果异常被捕获,程序可以继续执行。如果异常没有被处理,系统函数terminate()将被调用,进而调用abort()。严格来说,程序不会崩溃,而是_终止_。 - CouchDeveloper
终止导致了崩溃报告发送到我的分析系统,所以这对我的目的很有效。 - Katushai
2
为什么不直接调用abort()呢?抛出的异常可以被捕获,而abort()不能。在Mac上,abort()会生成一个崩溃日志,我想在iOS上也是这样的。 - Peter N Lewis
我不太确定崩溃分析SDK如何与abort()一起工作。原始问题是为了测试崩溃分析服务,因此使用本地的@throw语句是我最好的猜测。 - Stavash
这不是崩溃,只是一个异常,并导致触发 exc_breakpoint。 - NaXir

25

有很多种方法可以终止一个应用程序!这里有两个一行命令:

[self performSelector:@selector(die_die)];

同样也

@[][666];

调用 exit 不会导致崩溃。 - rmaddy
3
@maddy...您说得对,先生!感谢您让我的分数成为10的倍数。那额外的2分让我抓狂了。 - fsaint
2
我没有点踩,是别人点的。不要做出这样的假设。 - rmaddy
2
@maddy 抱歉指责你了。干杯! - fsaint
@[][666] 是什么意思?你能解释一下吗? - Jayprakash Dubey
10
@[] 表示一个空数组。666 是无法言说的某个实体的数字。任何数字都会导致崩溃,我选择了666以增加戏剧效果。 - fsaint

14

只需编写assert(NO)。这将检查作为参数给定的条件,如果为假,则使应用程序崩溃。

编辑:

exit(0)也可以实现相同的效果。


这个方法也起作用。虽然我不得不接受另一个答案,因为它先到了。非常好。这似乎是大多数人不知道会在iOS上引起崩溃的事情。 - Katushai
默认情况下不会启用,但很容易实现。请检查您的目标构建设置:Apple LLVM 5.0 - 预处理 > 启用 Foundation 断言。 - Desdenova
出于完整性考虑,我认为它应该是NSAssert,符合Cocoa的风格。但无论哪种方式都可以工作。 - Katushai

11
int* p = 0;
*p = 0;

出现 EXC_BAD_ACCESS (code=2, address=0x0) 错误。

编辑:

在 Greg Parker 的评论中,他指出编译器可以优化上述语句,这让我更加深入地思考了以上语句的原因:

事实上,在 C 和 C++ 中 解引用 NULL 指针 是“未定义行为”(也参见 C99 §6.5.3.2/4)。

这意味着,以上语句的效果取决于编译器。这种“未定义行为”还意味着编译器可以应用几种优化,这些优化可能导致以上语句被“优化掉”,正如 Greg Parker 所断言的那样。

现在,这让我很好奇 clang 到底会做什么:

这是一个小测试程序:

int main(int argc, const char * argv[])
{
    int* p = 0;
    *p = 0;
    return 0;
}

将优化设置为“-Ofast”,我们获得以下反汇编代码:

0x100000f90:  pushq  %rbp
0x100000f91:  movq   %rsp, %rbp
0x100000f94:  ud2    

其中ud2是一条指令,意思是“未定义的指令”,会导致CPU异常:

`EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)`

(也许@GregParker能够评论一下为什么clang选择这种方法?)

虽然这很有趣,但它只涉及“取消引用NULL指针”。 如果我们有以下情况:

int* p = (int*)1;
*p = 0;

程序会如预期一样崩溃 - 但需要“前提条件”,即硬件拒绝对此(无效)地址进行写入。


1
编译器可以将其优化掉。 - Greg Parker
@GregParker 是的,但这是一个不同的“问题” ;) - CouchDeveloper

10
我认为好久以前的数组索引越界是“成功崩溃”的保证,所以这是我的最爱列表:
Swift 4:
1. [][0] 2. fatalError()
Objective-C:
1. @[][0]; 2. int *x = nil; *x = 0;
尽管@throw NSInternalInconsistencyException;可以解决您的问题,但它是一个异常(而不是崩溃),因此可能会被捕获

6

我经常发现让应用程序启动,执行一段时间后在10秒后崩溃非常有用。在这种情况下(对于Objective-C),我使用以下代码:

[self performSelector:NSSelectorFromString(@"crashme:") withObject:nil afterDelay:10];

这样做的一个次要好处是,编译器不会抛出任何警告(如果使用Objective-C),表明选择器未找到。 :) Swift:
self.perform("crashme:", with: nil, afterDelay: 10)

3
更为可控的方式是自己抛出异常: @throw [NSException exceptionWithName:NSGenericException reason:@"" userInfo:nil]; 请查看NSException.h以获取更多异常信息。

2

对于Swift,以下方法适用:

assert(false, "sdf")

And this:

var hey:[Int] = []
hey[0] = 1

请解释为什么您的答案是问题的解决方案。 - Qix - MONICA WAS MISTREATED
1
我不知道为什么,也不真的关心。它崩溃了,并且只需要极少的代码就能触发。 - Esqarrouth
1
你是一个回答者,你应该关心。 - Qix - MONICA WAS MISTREATED
好的,在Swift中,数组不是这样工作的,通常我们应该在所选索引处向数组中添加元素。由于我们没有使用正常的方法,它会崩溃。 - Esqarrouth

-1
*(long*)0 = 0xDEADBEEF;

出现EXC_BAD_ACCESS错误


1
编译器可以对此进行优化处理。 - Greg Parker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接