Why would CFRelease(NULL) crash?

瘦欲@ 提交于 2019-12-03 18:00:57

问题


Is there a reason why CFRelease does not check for NULL? Isn't it unacceptable when [nil release]; free(NULL); delete NULL; all work perfectly fine?


回答1:


The source code to CoreFoundation is publicly available. Specifically, for Snow Leopard the code to CFRelease is in http://www.opensource.apple.com/source/CF/CF-550/CFRuntime.c

Here is what the relevant portion looks like:

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
}

This doesn't answer your question about design motivations, but you also asked why CFRelease does not check for NULL. It does check, and fails on purpose when NULL is passed as the parameter.

My personal belief is similar to Quinn's- that the CF designers felt it is a programming error to pass NULL.




回答2:


Good point, it doesn't seem to make much sense at first glance. Of course, the behavior is properly documented, but it would be nice if it could handle NULL gracefully. Notice that CFRetain and CFMakeCollectable (new in 10.4, GC enabled in 10.5) exhibit the same behavior. I'm not privy to all the motivations for designing it that way, but the emphasis was probably more on internal consistency with the rest of the CoreFoundation framework.

It's difficult/impossibly to know why CF was designed that way unless you can ask one of the designers. My best guess is that the designers decided that passing NULL for memory management functions is (should be?) a programming error. One could argue that causing a crash on NULL is a desirable "fail-fast" behavior, since bugs that crash almost immediately are easier to track down than bugs which silently do nothing instead of what you expect. Personally, I prefer the do-nothing-on-null approach, but I guess that's life...

Given that the API can't/won't change, you can either test for NULL or work around the problem case. One option might be to define an inline function or macro that only calls CFRelease for non-NULL references. In any case, it's probably best to be explicit in your code to avoid confusion down the road.




回答3:


All of these functions are part of different APIs that follow different conventions with regards to handling NULL:

  1. CFRelease is part of the CoreFoundation C SDK, which does not accept NULL reference as arguments by default.
  2. [nil release] uses Objective-C (which allows dereferences of nil)
  3. free(NULL) is part of C library (libc) which permits NULL arguments
  4. delete NULL is part of the C++ library (libc++) which permits NULL arguments

I guess the CoreFoundation SDK writers decided to be more consistent with the rest of SDK rather than with similar function in other SDKs.




回答4:


You may have a look at the source code of CFReleaseProtector to get a handle on (or better understanding of) this issue.

CFRelease no more crash on NULL,

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

You may unpack CFReleaseProtector.sit with the command line tool unar (part of The Unarchiver; see its Google code downloads list).



来源:https://stackoverflow.com/questions/1135214/why-would-cfreleasenull-crash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!