【问题标题】:Why would CFRelease(NULL) crash?为什么 CFRelease(NULL) 会崩溃?
【发布时间】:2009-07-16 03:06:32
【问题描述】:

CFRelease 不检查 NULL 是否有原因? [nil release] 时是不是不能接受;免费(空);删除空;一切正常吗?

【问题讨论】:

    标签: objective-c core-foundation


    【解决方案1】:

    CoreFoundation 的源代码是公开的。具体来说,对于 Snow Leopard,CFRelease 的代码位于 http://www.opensource.apple.com/source/CF/CF-550/CFRuntime.c

    下面是相关部分的样子:

    void CFRelease(CFTypeRef cf) {
        if (NULL == cf) HALT;
    #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
        if (CF_IS_COLLECTABLE(cf)) {
            if (CFTYPE_IS_OBJC(cf)) {
                // release the GC-visible reference.
                auto_zone_release(auto_zone(), (void*)cf);
            } else {
                // special-case CF objects for better performance.
                _CFRelease(cf);
            }
            return;
        }
    #endif
    }
    

    这并没有回答您关于设计动机的问题,但您还问了为什么 CFRelease 不检查 NULL。它确实会检查,并在将 NULL 作为参数传递时故意失败。

    我个人的看法与 Quinn 的相似——CF 设计者认为传递 NULL 是一个编程错误。

    【讨论】:

      【解决方案2】:

      好点子,乍一看似乎没有多大意义。当然,behavior is properly documented,但如果它能够优雅地处理NULL,那就太好了。请注意,CFRetainCFMakeCollectable(10.4 中新增,10.5 中启用了 GC)表现出相同的行为。我并不了解以这种方式设计它的所有动机,但重点可能更多地在于与 CoreFoundation 框架的其余部分的内部一致性。

      很难/不可能知道为什么 CF 是这样设计的,除非您可以询问其中一位设计师。我最好的猜测是,设计者认为为内存管理函数传递 NULL 是(应该是?)一个编程错误。有人可能会争辩说,在 NULL 上导致崩溃是一种理想的“快速失败”行为,因为几乎立即崩溃的 bug 比默默不做任何事情而不是你所期望的 bug 更容易追踪。就个人而言,我更喜欢什么都不做的方法,但我想这就是生活......

      鉴于 API 不能/不会更改,您可以测试 NULL 或解决问题案例。一种选择可能是定义一个只为非 NULL 引用调用 CFRelease 的内联函数或宏。无论如何,最好在您的代码中明确说明,以避免以后出现混淆。

      【讨论】:

      • 考虑 Quartz CGImageRelease 和类似的确实接受 NULL:“这个函数相当于 CFRelease,除了如果图像参数为 NULL 它不会导致错误。”
      • 好吧,这很好,但那是在 CoreGraphics 中,而不是在 Core Foundation 中。如果 CFRelease 和朋友被更改为 not 在传递 NULL 时崩溃,它可能会在现有代码中导致意外结果(尽管希望没有人故意以这种方式导致崩溃)并使习惯于该行为的 CoreFoundation 程序员感到困惑。即便如此,我倾向于同意你的观点。
      【解决方案3】:

      所有这些函数都是不同 API 的一部分,它们在处理 NULL 方面遵循不同的约定:

      1. CFRelease 是 CoreFoundation C SDK 的一部分,默认情况下不接受 NULL 引用作为参数。
      2. [nil release] 使用 Objective-C(允许取消引用 nil
      3. free(NULL) 是 C 库 (libc) 的一部分,它允许 NULL 参数
      4. delete NULL 是 C++ 库 (libc++) 的一部分,它允许 NULL 参数

      我猜CoreFoundation SDK 编写者决定与 SDK 的其余部分保持一致,而不是与其他 SDK 中的类似功能保持一致。

      【讨论】:

      • 对我来说,这个答案几乎是说:CFRelease 崩溃是因为 CF 以这种方式工作。 free(NULL) 不会崩溃,因为 C 标准是这样说的。 delete NULL 不会崩溃,因为 C++ 标准是这样说的。它没有回答我的问题。我在问为什么 CF SDK 设计者故意决定让他们的公共 API 使程序崩溃。
      • 没有直接询问 CF 设计师(假设他们可以/会告诉你原因),我们只是在猜测。我已经在我的回答中提出了我的最佳猜测。
      • 如果您要问的问题只有编写此 API 的人才能回答,为什么要问 SO? SO 的重点是提出社区可以回答的问题。
      • 您的“社区”似乎不包括可能知道原因的 Apple 开发人员。
      【解决方案4】:

      您可以查看 CFReleaseProtector 的源代码来处理(或更好地理解)这个问题。

      CFRelease NULL 不再崩溃,

      http://unsanity.org/archives/haxies/cfrelease_no_mo.php

      您可以使用命令行工具 unar(The Unarchiver 的一部分;参见其 Google 代码下载列表)解压缩 CFReleaseProtector.sit。

      【讨论】:

      • 仍然崩溃(iOS 9)。
      猜你喜欢
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 2013-01-31
      • 2014-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多