Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C Singletons and LLVM/clang leak warnings

I'm using the singleton pattern in several places in an application, and I'm getting memory leak errors from clang when analyzing the code.

static MyClass *_sharedMyClass;
+ (MyClass *)sharedMyClass {
  @synchronized(self) {
    if (_sharedMyClass == nil)
      [[self alloc] init];
  }
  return _sharedMyClass;
}

// clang error: Object allocated on line 5 is no longer referenced after this point and has a retain count of +1 (object leaked)

I'm using these settings for scan-build:

scan-build -v -v -v -V -k xcodebuild

I'm fairly certain that the code in the singleton is just fine - after all, it's the same code referenced here on Stack Overflow as well as in Apple's documentation - but I would like to get the memory leak warning sorted out so my scan-build returns success.

like image 638
pix0r Avatar asked Dec 20 '25 03:12

pix0r


2 Answers

I may be being exceptionally dense, but surely your line 5

[[self alloc] init];

allocates an object of the containing class type, and promptly throws it away? Do you not want

_sharedMyClass = [[self alloc] init];

?

like image 193
Adam Wright Avatar answered Dec 22 '25 16:12

Adam Wright


Apple has since updated their recommended singleton code to pass the static analyzer:

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
    return [[self sharedManager] retain];
}

Now +sharedManager calls super's -allocWithZone: and assigns the return of -init, and the singleton's -allocWithZone: just returns a retained sharedInstance.

Edit:

Why the retain in +allocWithZone:?

+allocWithZone: is overridden because someone using MyGizmoClass could circumvent the singleton by calling [[MyGizmoClass alloc] init] instead of [MyGizmoClass sharedManager]. It's retained because +alloc is expected to always return an object with a retain count of +1.

Every call to +alloc should be balanced with a -release or -autorelease, so without the retain in +allocWithZone:, the shared instance could potentially be deallocated out from under other users.

like image 42
2 revsJustin Anderson Avatar answered Dec 22 '25 16:12

2 revsJustin Anderson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!