discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Deadlock in NSUserDefaults


From: Larry Campbell
Subject: Re: Deadlock in NSUserDefaults
Date: Fri, 6 Jun 2008 18:33:04 -0400

On Jun 6, 2008, at 6:12 PM, Larry Campbell wrote:

I just found a deadlock bug in NSUserDefaults. I think this may be the same bug as the one mbruen@smartsoft.de reported last year under the subject line "NSRecursiveLock hangs".

Here's a timeline. Line numbers refer to NSUserDefaults.m in gnustep- base 1.13.0 (although a quick glance at 1.14.1 leads me to believe it still has the same bug). All of the instance methods are being called on the same instance, the default NSUserDefaults object.

thread 1 calls -[NSUserDefaults synchronize], which acquires _lock (line 1588) and calls -[NSUserDefaults writeDefaults] thread 1 -[NSUserDefaults writeDefaults] calls -[NSDictionary writeToFile:atomically:] thread 2 calls NSLog, which calls NSCalendarDate, which calls GSUserDefaultsDictionaryRepresentation thread 2 GSUserDefaultsDictionaryRepresentation acquires classLock (line 1968) thread 1 -[NSDictionary writeToFile:atomically:] calls GSUserDefaultsDictionaryRepresentation thread 1 GSUserDefaultsDictionaryRepresentation attempts to acquire classLock (line 1968) and hangs because thread 2 has it thread 2 GSUserDefaultsDictionaryRepresentation calls - [NSUserDefaults dictionaryRepresentation] thread 2 -[NSUserDefaults dictionaryRepresentation] attempts to acquire _lock (line 1765) and hangs because thread 1 has it

This is a classic lock ordering bug. One simple way to avoid it it to always follow the rule that whenever multiple locks are acquired, they must be acquired in the same order, and released in the reverse order. However, at first glance, it looks to me like making NSUserDefaults.m conform to this rule might require major surgery.

Although I think there may be other bugs lurking here, I think a localized fix for this one would be to change

NSDictionary*
GSUserDefaultsDictionaryRepresentation()
{
  NSDictionary  *defs;

  if (sharedDefaults == nil)
    {
      [NSUserDefaults standardUserDefaults];
    }
  [classLock lock];
  defs = [sharedDefaults dictionaryRepresentation];
  [classLock unlock];
  return defs;
}


to


NSDictionary*
GSUserDefaultsDictionaryRepresentation()
{
  NSUserDefaults *shared;

  if (sharedDefaults == nil)
    {
      [NSUserDefaults standardUserDefaults];
    }
  [classLock lock];
  shared = AUTORELEASE(RETAIN(sharedDefaults));
  [classLock unlock];
  return [shared dictionaryRepresentation];
}








reply via email to

[Prev in Thread] Current Thread [Next in Thread]