diff --git a/Headers/GNUstepBase/NSObject+GNUstepBase.h b/Headers/GNUstepBase/NSObject+GNUstepBase.h index 7c70ff988..cc4ccda05 100644 --- a/Headers/GNUstepBase/NSObject+GNUstepBase.h +++ b/Headers/GNUstepBase/NSObject+GNUstepBase.h @@ -212,46 +212,49 @@ extern "C" { + (void) atExit; @end -/** Category for methods handling leaked memory cleanup on exit of process +/** Category for methods handling leaked memory clean-up on exit of process * (for use when debugging memory leaks).
* You enable this by calling the +setShouldCleanUp: method (done implicitly * by gnustep-base if the GNUSTEP_SHOULD_CLEAN_UP environment variable is * set to YES).
- * Your class then has two options for performing cleanup when the process + * Your class then has two options for performing clean-up when the process * ends: - *

1. Use the +leak: method to register objects which are simply to be + *

1. Use the +leaked: method to register objects which are simply to be * retained until the process ends, and then either ignored or released - * depending on the cleanup setting in force. This mechanism is simple + * depending on the clean-up setting in force. This mechanism is simple * and should be sufficient for many classes. *

*

2. Implement a +atExit method to be run when the process ends and, * within your +initialize implementation, call +shouldCleanUp to determine - * whether cleanup should be done, and if it returns YES then call + * whether clean-up should be done, and if it returns YES then call * +registerAtExit to have your +atExit method called when the process * terminates. *

*

The order in which 'leaked' objects are released and +atExit methods * are called on process exist is the reverse of the order in which they - * werse set up suing this API. + * werse set up using this API. *

*/ -@interface NSObject(GSCleanup) +@interface NSObject(GSCleanUp) - -/** This method simply retains its argument so that it will never be - * deallocated during normal operation, but keeps track of it so that - * it is released during process exit if cleanup is enabled.
- * Returns its argument. +/** Returns YES if the process is exiting (and perhaps performing clean-up). */ -+ (id) NS_RETURNS_RETAINED leak: (id)anObject; ++ (BOOL) isExiting; -/** This method retains the object at *anAddress so that it will never be - * deallocated during normal operation, but keeps track of the address - * so that the object is released and the address is zeroed during process - * exit if cleanup is enabled.
- * Returns the object at *anAddress. +/** This method informs the system that the object at anAddress has been + * intentionally leaked (will not be deallocated by higher level code) + * and should be cleaned up at process exit (and the address content + * zeroed out) if clean-up is enabled. */ -+ (id) NS_RETURNS_RETAINED leakAt: (id*)anAddress; ++ (void) leaked: (id*)anAddress; + +/** Deprecated: use +leaked: instead. + */ ++ (id) NS_RETURNS_RETAINED leak: (id)anObject ;//GS_DEPRECATED_FUNC; + +/** Deprecated: use +leaked: instead. + */ ++ (id) NS_RETURNS_RETAINED leakAt: (id*)anAddress ;//GS_DEPRECATED_FUNC; /** Sets the receiver to have its +atExit method called at the point when * the process terminates.
@@ -269,10 +272,10 @@ extern "C" { */ + (BOOL) registerAtExit: (SEL)aSelector; -/** Specifies the default cleanup behavior on process exit ... the value +/** Specifies the default clean-up behavior on process exit ... the value * returned by the NSObject implementation of the +shouldCleanUp method.
* Calling this method with a YES argument implicitly enables the support for - * cleanup at exit.
+ * clean-up at exit.
* The GNUstep Base library calls this method with the value obtained from * the GNUSTEP_SHOULD_CLEAN_UP environment variable when NSObject is * initialised. diff --git a/Source/Additions/NSObject+GNUstepBase.m b/Source/Additions/NSObject+GNUstepBase.m index 4818693d9..6b14eed96 100644 --- a/Source/Additions/NSObject+GNUstepBase.m +++ b/Source/Additions/NSObject+GNUstepBase.m @@ -156,6 +156,7 @@ struct exitLink { static struct exitLink *exited = 0; static BOOL enabled = NO; static BOOL shouldCleanUp = NO; +static BOOL isExiting = NO; static NSLock *exitLock = nil; static inline void setup() @@ -176,7 +177,10 @@ static inline void setup() static void handleExit() { - BOOL unknownThread = GSRegisterCurrentThread(); + BOOL unknownThread; + + isExiting = YES; + unknownThread = GSRegisterCurrentThread(); CREATE_AUTORELEASE_POOL(arp); while (exited != 0) @@ -212,9 +216,32 @@ handleExit() { GSUnregisterCurrentThread(); } + isExiting = NO; } -@implementation NSObject(GSCleanup) +@implementation NSObject(GSCleanUp) + ++ (BOOL) isExiting +{ + return isExiting; +} + ++ (void) leaked: (id*)anAddress +{ + struct exitLink *l; + + NSAssert(*anAddress && [*anAddress isKindOfClass: [NSObject class]], + NSInvalidArgumentException); + l = (struct exitLink*)malloc(sizeof(struct exitLink)); + l->at = anAddress; + l->obj = *anAddress; + l->sel = 0; + setup(); + [exitLock lock]; + l->next = exited; + exited = l; + [exitLock unlock]; +} + (id) leakAt: (id*)anAddress { diff --git a/Source/NSArray.m b/Source/NSArray.m index ea966e873..828c739b5 100644 --- a/Source/NSArray.m +++ b/Source/NSArray.m @@ -105,7 +105,15 @@ static SEL rlSel; + (void) atExit { - DESTROY(defaultPlaceholderArray); + id o; + + /* The default placeholder array overrides -dealloc so we must get rid of + * it directly. + */ + o = defaultPlaceholderArray; + defaultPlaceholderArray = nil; + NSDeallocateObject(o); + DESTROY(placeholderMap); } diff --git a/Source/NSString.m b/Source/NSString.m index d73985ee3..91077a9dd 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -166,9 +166,13 @@ static NSMapTable *placeholderMap; static gs_mutex_t placeholderLock = GS_MUTEX_INIT_STATIC; -static SEL cMemberSel = 0; -static NSCharacterSet *nonBase = nil; -static BOOL (*nonBaseImp)(id, SEL, unichar) = 0; +static SEL cMemberSel = 0; +static NSCharacterSet *nonBase = nil; +static BOOL (*nonBaseImp)(id, SEL, unichar) = 0; + +static NSCharacterSet *wPathSeps = nil; +static NSCharacterSet *uPathSeps = nil; +static NSCharacterSet *rPathSeps = nil; /* Macro to return the receiver if it is already immutable, but an * autoreleased copy otherwise. Used where we have to return an @@ -308,9 +312,6 @@ GSPathHandling(const char *mode) static NSCharacterSet* pathSeps(void) { - static NSCharacterSet *wPathSeps = nil; - static NSCharacterSet *uPathSeps = nil; - static NSCharacterSet *rPathSeps = nil; if (GSPathHandlingRight()) { if (rPathSeps == nil) @@ -318,9 +319,8 @@ pathSeps(void) GS_MUTEX_LOCK(placeholderLock); if (rPathSeps == nil) { - rPathSeps - = [NSCharacterSet characterSetWithCharactersInString: @"/\\"]; - rPathSeps = [NSObject leakAt: &rPathSeps]; + rPathSeps = RETAIN([NSCharacterSet + characterSetWithCharactersInString: @"/\\"]); } GS_MUTEX_UNLOCK(placeholderLock); } @@ -333,9 +333,8 @@ pathSeps(void) GS_MUTEX_LOCK(placeholderLock); if (uPathSeps == nil) { - uPathSeps - = [NSCharacterSet characterSetWithCharactersInString: @"/"]; - uPathSeps = [NSObject leakAt: &uPathSeps]; + uPathSeps = RETAIN([NSCharacterSet + characterSetWithCharactersInString: @"/"]); } GS_MUTEX_UNLOCK(placeholderLock); } @@ -348,9 +347,8 @@ pathSeps(void) GS_MUTEX_LOCK(placeholderLock); if (wPathSeps == nil) { - wPathSeps - = [NSCharacterSet characterSetWithCharactersInString: @"\\"]; - wPathSeps = [NSObject leakAt: &wPathSeps]; + wPathSeps = RETAIN([NSCharacterSet + characterSetWithCharactersInString: @"\\"]); } GS_MUTEX_UNLOCK(placeholderLock); } @@ -881,6 +879,10 @@ register_printf_atsign () + (void) atExit { DESTROY(placeholderMap); + DESTROY(nonBase); + DESTROY(rPathSeps); + DESTROY(uPathSeps); + DESTROY(wPathSeps); } + (void) initialize @@ -900,7 +902,6 @@ register_printf_atsign () ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:); nonBase = [NSCharacterSet nonBaseCharacterSet]; - nonBase = [NSObject leakAt: &nonBase]; nonBaseImp = (BOOL(*)(id,SEL,unichar))[nonBase methodForSelector: cMemberSel]; @@ -3951,9 +3952,13 @@ register_printf_atsign () } else { + BOOL result; + + ENTER_POOL NSData *d = [self dataUsingEncoding: encoding]; unsigned length = [d length]; - BOOL result = (length < maxLength) ? YES : NO; + + result = (length < maxLength) ? YES : NO; if (d == nil) { @@ -3966,6 +3971,7 @@ register_printf_atsign () } memcpy(buffer, [d bytes], length); buffer[length] = '\0'; + LEAVE_POOL return result; } } @@ -4279,7 +4285,7 @@ register_printf_atsign () if (GSFromUnicode(&b, &l, u, len, encoding, NSDefaultMallocZone(), options) == YES) { - d = [NSDataClass dataWithBytesNoCopy: b length: l]; + d = [NSDataClass dataWithBytesNoCopy: b length: l freeWhenDone: YES]; } else {