在Mac上调用CFNetworkExecuteProxyAutoConfigurationURL时泄漏

时间:2018-11-13 23:10:41

标签: memory-leaks proxy cfnetwork cfrunloop

我正在使用CFNetwork API来检测OS代理设置。我的设置主要基于此: https://github.com/adobe/chromium/blob/master/net/proxy/proxy_resolver_mac.cc 几乎与此相同: https://developer.apple.com/library/archive/samplecode/CFProxySupportTool/Introduction/Intro.html

我使用CFNetworkCopyProxiesForURL来获取代理列表,对于PAC类型,使用CFNetworkExecuteProxyAutoConfigurationURL来获取并执行PAC脚本,立即在当前线程上运行运行循环,而该线程已经不在ui线程上。

这一切都正常工作,并且我已仔细检查以确保我遵循创建规则以正确发布结果。但是,当使用Xcode工具时,我看到_CFNetworkExecuteProxyAutoConfigurationURLDelegated泄漏到PAC :: PACClient的std :: shared_ptrs。由于该对象从未暴露给我,因此我不确定如何控制它的释放,但它正在泄漏。这只是获取PAC文件的问题,显式代理不会泄漏。我曾尝试在所有CFDictionaries上添加冗余CFRelease调用,然后向我公开这些调用以查看是否保留了某些内容,但这对PACClient泄漏没有任何影响。

在Mac上的ARC项目中,它是cpp文件而不是目标C。

有人遇到过这种泄漏并且知道如何预防吗?

下面是执行查找的代码段,与上述项目的步骤相同。

struct PACRequestInfo {
    CFURLRef url; // Caller gets this from a dictionary, doesn't need release
    CFURLRef scriptURL; // Caller gets this from a dictionary, doesn't need release
    CFMutableArrayRef proxies; // Reference to a dictionary that is released by the caller
};

void resultCallback(void* client, CFArrayRef proxies, CFErrorRef error) {
    // Error handling removed for brevity
    if (CFTypeRef* resultPtr = (CFTypeRef*) client)
        *resultPtr = CFRetain(proxies);

    CFRunLoopStop(CFRunLoopGetCurrent());
}

// Provided PACRequestInfo is created on the stack by the caller
void doPACRequest(const PACRequestInfo& info) {
    CFTypeRef result = nullptr;
    CFStreamClientContext context = { 0, &result, nullptr, nullptr, nullptr };
    // Scoped ptr not shown but just calls CFRelease on destruction
    CFScopedPtr<CFRunLoopSourceRef> runLoopSource(CFNetworkExecuteProxyAutoConfigurationURL(info.scriptURL, info.url, resultCallback, &context));
    if (runLoopSource) {
        const static CFStringRef  kPrivateRunLoopMode = CFSTR("myprivateloop");
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kPrivateRunLoopMode);
        CFRunLoopRunInMode(kPrivateRunLoopMode, 1.0e10, false);
        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kPrivateRunLoopMode);

        if (result && CFGetTypeID(result) == CFArrayGetTypeID()) {
            CFArrayRef resultArray = (CFArrayRef) result;
            CFArrayAppendArray(info.proxies, resultArray, CFRangeMake(0, CFArrayGetCount(resultArray)));
        }
    }

    // Retain was called on this value during ResultCallback.
    if (result) {
        CFRelease(result);
    }
}

0 个答案:

没有答案