11

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?

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
Dave Martorana
  • 1,321
  • 13
  • 21

6 Answers6

4

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;
}
mekentosj
  • 116
  • 6
3

It is a bug in the implementation of _NSCFURLProtocolBridge.

Please use http://bugreport.apple.com/ and file a bug. If you include the URL to this page, that would be appreciated (and if you update this page with the Radar #, that would be appreciated, too). Ideally, if you can attach a binary of your screensaver, that would be very helpful; no source needed.

Fortunately, it should not cause a crash. Unfortunately, it probably causes a leak.

bbum
  • 162,346
  • 23
  • 271
  • 359
1

This error generally indicates that an object was retained with -retain, but released with CFRelease(). If you believe that this could not be your object (and that's not a terrible belief), then you should open another Radar. But you should first look around and see if there's a CF object you're using -retain on when perhaps you should use CFRetain().

The rest of this is shooting in the dark....

You may gain some insight by stepping up the stack and looking at the parameters that are being passed to these C++ methods (or particularly auto_zone_release). Try this in gdb to try to see what's in the first parameter:

p *($esp)

And see if you can get any insight about the object being passed. Perhaps this will work if you're lucky:

po (id)(*($esp))
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Rob - in a GC environment, aren't -retain calls NOOPs? I do think this is a bug and I will open a Radar bug about it. Thanks! – Dave Martorana Jul 28 '09 at 14:26
  • 1
    -retain is a NOOP in GC, but CFRetain() is not. So if you call -retain and then CFRelease(), you'll get unbalanced. – Rob Napier Jul 28 '09 at 15:01
1

I worked around this issue by CFRetain-ing the client, and CFRelease-ing it again on the next call to startLoading

-(void)startLoading 
{
        if ( client ) CFRelease(client);
        client = [self client];
        CFRetain(client);

and, of course, in finalize

-(void)finalize
{
    if ( client ) CFRelease(client);
    [super finalize];
}

client is an instance variable of the NSURLProtocol subclass.

Drew McCormack
  • 3,490
  • 1
  • 19
  • 23
1

Here is the bug report I had filed a while back:

http://openradar.appspot.com/8087384

Probably worth filing as well, it's already been dup-ed, but it would be nice to get it fixed.

As Alex said, an Apple developer looked at the source code in front of me and located the issue easily with the example we had.

Quinn Taylor
  • 44,553
  • 16
  • 113
  • 131
charles
  • 11,212
  • 3
  • 31
  • 46
0

the same error comes sometimes using NSURL in open dialog filter. for me it was enough to set it to nil explicitly after I don't need it anymore.

psaghelyi
  • 500
  • 4
  • 12