为CFHostRef调用CFRelease有时会崩溃

时间:2015-06-16 18:44:54

标签: objective-c core-foundation

这是我今天早些时候发表的一篇文章中提出的第二个问题。我有下面的方法,它适用于我需要的,但有时当我在CFRelease变量上调用hostRef时崩溃。我认为它可能与我试图释放它时在其他地方使用的资源有关,但据我所知,我正在同步解析主机而我不会从另一个线程访问它。

我尝试在CFHostCancelInfoResolution之前调用CFRelease,但这并没有改变崩溃的频率。我想我会在这里张贴这个,看看是否有一些假设或误解我不是真的。

+ (NSArray *) addressesForHostname: (NSString *)hostname {

    CFMutableArrayRef ipAddresses = nil;

    DLog(@"Getting addresses for host name %@", hostname);

    CFHostRef hostRef = CFHostCreateWithName(kCFAllocatorDefault, (__bridge CFStringRef)(hostname));
    CFStreamError error;

    BOOL didResolve = CFHostStartInfoResolution(hostRef, kCFHostAddresses, &error); // synchronously get the host.

    if (didResolve) {

        CFArrayRef responseObjects = CFHostGetAddressing(hostRef, NULL);
        long numberOfResponses = CFArrayGetCount(responseObjects);
        ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault, numberOfResponses, &kCFTypeArrayCallBacks);

        for ( int i = 0 ; i < numberOfResponses; ++i ) {

            char * ipAddress = NULL;
            CFDataRef responseObject = CFArrayGetValueAtIndex(responseObjects, i);
            struct sockaddr * currentAddress = (struct sockaddr *) CFDataGetBytePtr(responseObject); // Unwrap the CFData wrapper aound the sockaddr struct

            switch (currentAddress->sa_family) {

                case AF_INET: { // Internetworking AKA IPV4

                    DLog(@"Extracting IPV4 address");
                    struct sockaddr_in * socketAddress = (struct sockaddr_in *) currentAddress;

                    ipAddress = malloc(sizeof(INET_ADDRSTRLEN));
                    inet_ntop(AF_INET,
                              &(socketAddress->sin_addr),
                              ipAddress,
                              INET_ADDRSTRLEN);

                    CFStringRef ipAddressString = CFStringCreateWithCString(kCFAllocatorDefault, ipAddress, kCFStringEncodingASCII);
                    CFArrayInsertValueAtIndex(ipAddresses, i, ipAddressString);

                    break;

                }

                case AF_INET6: { // IPV6

                    DLog(@"Extracting IPV6 address");
                    struct sockaddr_in6 * socketAddress = (struct sockaddr_in6 *) currentAddress;

                    ipAddress = malloc(sizeof(INET6_ADDRSTRLEN));
                    inet_ntop(AF_INET6,
                              &(socketAddress->sin6_addr),
                              ipAddress,
                              INET6_ADDRSTRLEN);

                    CFStringRef ipAddressString = CFStringCreateWithCString(kCFAllocatorDefault, ipAddress, kCFStringEncodingASCII);
                    CFArrayInsertValueAtIndex(ipAddresses, i, ipAddressString);

                    break;
                }

                default:
                    DLog(@"Unsupported addressing protocol encountered. Gracefully ignoring and continuing.");
                    break;
            }

            if(ipAddress != NULL) {
                free(ipAddress);
            }
        }

        CFRelease(responseObjects);

    }

    CFRelease(hostRef);

    return (__bridge_transfer NSArray *) ipAddresses;
}

3 个答案:

答案 0 :(得分:1)

删除CFRelease(responseObjects);将解决它

答案 1 :(得分:1)

您必须遵循Core Foundation对象的创建规则。如果您通过调用其名称中包含“创建”或“复制”字样的函数(或者如果您明确调用CFRetain)来接收该对象,则必须在完成该对象时释放(CFRelease)该对象。如果您没有以这种方式接收对象,则不得释放该对象。

您的代码中存在多个错误。首先,您要找到的那个,即responseObjects左右。您使用以下方法获取此对象:

CFDataRef responseObject = CFArrayGetValueAtIndex(responseObjects, i);

该功能的名称中没有“创建”或“复制”。您不得在其上拨打CFRelease

但是,你也称之为:

ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault, numberOfResponses, &kCFTypeArrayCallBacks);

并且在几个地方:

CFStringRef ipAddressString = CFStringCreateWithCString(kCFAllocatorDefault, ipAddress, kCFStringEncodingASCII);

您必须在这些对象超出范围之前调用CFRelease,否则您将泄露它们。

答案 2 :(得分:0)

我认为CFStreamError error;可能会导致此问题。

尝试将错误声明为null?

// synchronously get the host.
BOOL didResolve = CFHostStartInfoResolution(hostRef, kCFHostAddresses, NULL);