如何重现罕见的“ _CFAutoReleasePoolPop”崩溃?

时间:2019-10-28 20:08:16

标签: ios objective-c core-foundation nsautoreleasepool manual-retain-release

我正在尝试重现此类崩溃: enter image description here

我的项目中有手动参考计数。另外,还有很多多线程。 一些属性不是线程安全的。 :(
我只有一个关于导致崩溃的原因的假设:某些对象被过分释放(?)

我添加了自动UI测试(Appium),但它们仍无济于事。
另外,我已经为Zombies进行了配置-一切正常。
另外,我尝试了Xcode的静态分析器(Product -> Analyze),虽然有很多警告,但是似乎都没有引起此类崩溃的原因(我看过警告Incorrect decrement of reference count not owned at this point )。

我用MRC创建了一个测试项目,并添加了以下代码:

- (void)testAssumptions {
    //@autoreleasepool
    {
        [self overReleaseNilValue];
        [self overReleaseNotNilValue];
    }
}

- (void)overReleaseNilValue {
    NSIndexPath* path = [[NSIndexPath alloc] initWithIndex:42];
    [path release];
    [path release];
}

- (void)overReleaseNotNilValue {
    NSIndexPath* path = nil;
    [path release];
    [path release];
}

在启用自动释放池或没有池的情况下,两次释放对象都不会崩溃。

所以我的问题是:
1.除了释放已释放的对象之外,此类崩溃的另一个原因是什么?
2.是否有办法增加重现这种崩溃的可能性?例如。一些环境变量,从而减少了对不安全代码的某些自动释放池容忍度?还是其他一些自动释放池?
3.为什么我的测试项目代码不会崩溃?

任何评论都将受到赞赏。

1 个答案:

答案 0 :(得分:2)

  

此时尚未拥有的引用计数递减不正确

这绝对是探索的警告。几乎可以肯定,您至少会指出一个错误。

您的测试项目实际上并没有测试任何东西(我相信它们也被反向命名)。无法保证过度释放值会导致崩溃。 overReleaseNotNilValue是明确定义的行为,绝对不会崩溃(将消息发送到nil不会执行任何操作)。 overReleaseNilValue是未定义的行为。我还没有深入研究它,但是我希望NSIndexPath用带标记的指针实现,如果您过度释放它们,则不会崩溃。

未定义是未定义。这并不意味着崩溃。过度释放值可以做任何事情。如果幸运的话,它会崩溃的。...

  

此外,还有很多多线程。一些属性不是线程安全的。

我希望这是间歇性问题的核心。我从事过此类项目。解决方案是解决问题。您将不知道哪个特定问题是导致崩溃的原因。您可能永远不会知道。您仍然必须修复所有问题。这将需要一些时间,但是您必须使代码成为线程安全的,否则它的行为是不确定的。

关于调试,您将需要按顺序执行以下操作:

  • 打开“运行时清理”选项(在“方案”编辑器中的“运行”,“诊断”下)。您尤其希望为此使用Thread Sanitizer。

  • 清除所有静态分析器警告。如果他们中有人说您的内存管理有误,请必须清除它们。系统从字面上告诉您问题出在哪里。不要忽略它。

  • 清除所有警告。您的项目中应该有零个警告。如果有很多“错误”警告,那么您将永远看不到真正的警告,告诉您问题出在哪里。消除所有警告。

我花了8个月的时间来消除一个专家开发人员编写的,写得很好并且几乎没有线程的项目中罕见的过发布崩溃。这可能需要很多时间。您必须清除所有问题。仅仅一个不正确的发行版本就足以使程序随机崩溃。