Утечка при вызове CFNetworkExecuteProxyAutoConfigurationURL на Mac - PullRequest
0 голосов
/ 14 ноября 2018

Я использую 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);
    }
}
...