diff --git a/ChangeLog b/ChangeLog index 259c727e5..74d7096e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,9 @@ Roland Schwingel reported that it caught legitimate files on windows. * Source/NSMessagePort.m: * Source/NSSocketPort.m: - Protect -release with lock and remove port from gloibal table within + * Source/NSIndexPath.m: + * Source/NSBundle.m: + Protect -release with lock and remove object from global table within protected region, to avoid possible double deallocation in a multithreaded process. diff --git a/Source/NSBundle.m b/Source/NSBundle.m index 35395091a..1a251f582 100644 --- a/Source/NSBundle.m +++ b/Source/NSBundle.m @@ -1428,6 +1428,19 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory) return YES; } +- (void) release +{ + /* We lock during release so that other threads can't grab the + * object between us checking the reference count and deallocating. + */ + [load_lock lock]; + if (NSDecrementExtraRefCountWasZero(self)) + { + [self dealloc]; + } + [load_lock unlock]; +} + /* This method is the backbone of the resource searching for NSBundle. It constructs an array of paths, where each path is a possible location for a resource in the bundle. The current algorithm for searching goes: diff --git a/Source/NSIndexPath.m b/Source/NSIndexPath.m index f739b011c..ff34d2251 100644 --- a/Source/NSIndexPath.m +++ b/Source/NSIndexPath.m @@ -31,6 +31,7 @@ #include #include #include +#include "GNUstepBase/GSLock.h" static NSLock *lock = nil; static NSHashTable *shared = 0; @@ -72,7 +73,7 @@ static NSIndexPath *dummy = nil; dummy = (NSIndexPath*)NSAllocateObject(self, 0, NSDefaultMallocZone()); shared = NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 1024); NSHashInsert(shared, empty); - lock = [NSLock new]; + lock = [GSLazyRecursiveLock new]; } } @@ -130,7 +131,7 @@ static NSIndexPath *dummy = nil; GSNOSUPERDEALLOC; } -- (NSString*)description +- (NSString*) description { NSMutableString *m = [[super description] mutableCopy]; unsigned i; @@ -425,5 +426,25 @@ static NSIndexPath *dummy = nil; return _length; } +- (void) release +{ + if (self != empty) + { + /* We lock the table while checking, to prevent + * another thread from grabbing this object while we are + * checking it. + * If we are going to deallocate the object, we first remove + * it from the table so that no other thread will find it + * and try to use it while it is being deallocated. + */ + [lock lock]; + if (NSDecrementExtraRefCountWasZero(self)) + { + [self dealloc]; + } + [lock unlock]; + } +} + @end