Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid reference count underflow in _NSCFURLProtocolBridge in custom NSURLProtocol in GC environment

The basics are I have a custom NSURLProtocol. In startLoading, [self client] is of type:

<_NSCFURLProtocolBridge> {NSURLProtocol, CFURLProtocol}

The problem is running this in a garbage-collected environment. Because I'm writing a screensaver, I'm forced to make it garbage-collected. However, the _NSCFURLProtocolBridge protocol seems to always throw:

malloc: reference count underflow for (memory_id_here), break on auto_refcount_underflow_error to debug

An example dump to the debug console is:

ScreenSaverEngine[1678:6807] client is <_NSCFURLProtocolBridge 0x20025ab00> {NSURLProtocol 0x200258ec0, CFURLProtocol 0x20029c400} ScreenSaverEngine(1678,0x102eda000) malloc: reference count underflow for 0x20025ab00, break on auto_refcount_underflow_error to debug.

You can see that the underflow occurs for <_NSCFURLProtocolBridge 0x20025ab00>.

When I break on auto_refcount_underflow_error, it seems to stack-trace back up to URLProtocolDidFinishLoading: in:

id client = [self client];
...
[client URLProtocolDidFinishLoading:self];

This problem seems to have existed for a while, but there seems to be no answer at all online:

http://lists.apple.com/archives/cocoa-dev/2008/May/msg01272.html http://www.cocoabuilder.com/archive/message/cocoa/2007/12/17/195056

The bug only shows itself in garbage-collected environments for these listed bugs as well. Any thoughts on how I can work around this without causing memory issues? I'm assuming this probably has something to do with the CF type underneath NSURLProtocol being released improperly?

like image 393
Dave Martorana Avatar asked Jul 11 '09 03:07

Dave Martorana


1 Answers

Last WWDC we confirmed this bug with a webkit engineer, he could see the bug right there in the code so hopefully they'll fix it. The workaround is to CFRetain the client in the initWithRequest method.

- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client
{
    // work around for NSURLProtocol bug
    // note that this leaks!
    CFRetain(client);

    if (self = [super initWithRequest:request cachedResponse:cachedResponse client:client])
    {
    }

    return self;
}
like image 89
mekentosj Avatar answered Sep 18 '22 20:09

mekentosj