Утечка при вызове CFNetworkExecuteProxyAutoConfigurationURL на Mac
Я использую API CFNetwork для определения настроек прокси ОС. Моя установка в значительной степени основана на этом: 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, немедленно выполняя цикл выполнения в текущем потоке, который уже отсутствует в потоке пользовательского интерфейса.
Все это работает правильно, и я тщательно прочесал, следя за тем, чтобы следовать правилам создания, чтобы правильно публиковать результаты. Однако при использовании инструментов Xcode я вижу, что std::shared_ptrs в PAC::PACClient просочились через _CFNetworkExecuteProxyAutoConfigurationURLDelegated. Так как этот объект никогда не подвергается мне, я не уверен, как я могу контролировать его высвобождение, но он протекает. Это проблема только при получении файлов PAC, явные прокси не пропускают. Я попытался добавить избыточные вызовы CFRelease ко всем CFDictionaries и тому подобному, выставленному мне, чтобы проверить, не было ли что-то перенесено, но это не имело значения для утечки PACClient.
Это на Mac в файле cpp, а не в C, в проекте с включенным ARC.
Кто-нибудь сталкивался с этой утечкой и знает, как ее предотвратить?
Ниже приведен фрагмент, который выполняет поиск, который является все теми же шагами из вышеупомянутых проектов.
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);
}
}