From 018111efbbff756ef52fc665564e3c3d87afc03b Mon Sep 17 00:00:00 2001 From: rfm Date: Sat, 30 Nov 2024 18:23:48 +0000 Subject: [PATCH] LeakSanitizer fixups for gcc and gnu runtime --- Source/GSFileHandle.m | 44 +++++++++-------- Source/NSKeyValueObserving.m | 49 +++++++++++-------- Tests/base/Functions/runtime.m | 2 + Tests/base/NSArray/general.m | 6 +-- Tests/base/NSAutoreleasePool/autorelease_eh.m | 8 +-- Tests/base/NSData/general.m | 10 ++-- Tests/base/NSFileHandle/singleton.m | 4 +- Tests/base/NSFileManager/general.m | 3 ++ Tests/base/NSIndexPath/general.m | 9 ++-- Tests/base/NSObject/test00.m | 2 + Tests/base/NSOperation/threads.m | 4 +- Tests/base/lsan.txt | 2 + 12 files changed, 84 insertions(+), 59 deletions(-) create mode 100644 Tests/base/lsan.txt diff --git a/Source/GSFileHandle.m b/Source/GSFileHandle.m index 83af1fec24..12e0c04c14 100644 --- a/Source/GSFileHandle.m +++ b/Source/GSFileHandle.m @@ -189,21 +189,45 @@ + (id) allocWithZone: (NSZone*)z - (void) dealloc { + [self ignoreReadDescriptor]; + [self ignoreWriteDescriptor]; + + /* If a read operation is in progress, we need to remove the handle + * from the run loop and destroy the operation information so that + * we won't generate a notification about it failing. + */ + if (readInfo) + { + DESTROY(readInfo); + } + + /* If a write operation is in progress, we need to remove the handle + * from the run loop and destroy the operation information so that + * we won't generate a notification about it failing. + */ + if ([writeInfo count] > 0) + { + [writeInfo removeAllObjects]; + } + if (self == fh_stdin) { fh_stdin = nil; + DEALLOC [NSException raise: NSGenericException format: @"Attempt to deallocate standard input handle"]; } if (self == fh_stdout) { fh_stdout = nil; + DEALLOC [NSException raise: NSGenericException format: @"Attempt to deallocate standard output handle"]; } if (self == fh_stderr) { fh_stderr = nil; + DEALLOC [NSException raise: NSGenericException format: @"Attempt to deallocate standard error handle"]; } @@ -211,26 +235,6 @@ - (void) dealloc DESTROY(service); DESTROY(protocol); - /* If a read operation is in progress, we need to remove the handle - * from the run loop and destroy the operation information so that - * we won't generate a notification about it failing. - */ - if (readInfo) - { - [self ignoreReadDescriptor]; - DESTROY(readInfo); - } - - /* If a write operation is in progress, we need to remove the handle - * from the run loop and destroy the operation information so that - * we won't generate a notification about it failing. - */ - if ([writeInfo count] > 0) - { - [self ignoreWriteDescriptor]; - [writeInfo removeAllObjects]; - } - /* Finalize *after* ending read and write operations so that, if the * file handle needs to be closed, we don't generate any notifications * containing the deallocated object. Thanks to David for this fix. diff --git a/Source/NSKeyValueObserving.m b/Source/NSKeyValueObserving.m index b761a01413..0a874a6bb7 100644 --- a/Source/NSKeyValueObserving.m +++ b/Source/NSKeyValueObserving.m @@ -89,7 +89,7 @@ classTable = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 128); infoTable = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, - NSNonOwnedPointerMapValueCallBacks, 1024); + NSObjectMapValueCallBacks, 1024); dependentKeyTable = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSOwnedPointerMapValueCallBacks, 128); baseClass = NSClassFromString(@"GSKVOBase"); @@ -111,9 +111,9 @@ @interface GSKVOBase : NSObject */ @interface GSKVOReplacement : NSObject { - Class original; /* The original class */ - Class replacement; /* The replacement class */ - NSMutableSet *keys; /* The observed setter keys */ + Class original; /* The original class */ + Class replacement; /* The replacement class */ + NSMutableDictionary *keys; /* The observed setter keys */ } - (id) initWithClass: (Class)aClass; - (void) overrideSetterFor: (NSString*)aKey; @@ -475,16 +475,16 @@ - (id) initWithClass: (Class)aClass replacement = NSClassFromString(name); GSObjCAddClassBehavior(replacement, baseClass); - /* Create the set of setter methods overridden. + /* Create the dictionary of setter methods overridden. */ - keys = [NSMutableSet new]; + keys = [NSMutableDictionary new]; return self; } - (void) overrideSetterFor: (NSString*)aKey { - if ([keys member: aKey] == nil) + if ([keys objectForKey: aKey] == nil) { NSMethodSignature *sig; SEL sel; @@ -493,9 +493,13 @@ - (void) overrideSetterFor: (NSString*)aKey NSString *suffix; NSString *a[2]; unsigned i; + BOOL found = NO; NSString *tmp; - unichar u; + unichar u; +#if defined(USE_LIBFFI) + GSCodeBuffer *b = nil; +#endif suffix = [aKey substringFromIndex: 1]; u = uni_toupper([aKey characterAtIndex: 0]); @@ -610,10 +614,7 @@ - (void) overrideSetterFor: (NSString*)aKey else { #if defined(USE_LIBFFI) - GSCodeBuffer *b; - b = cifframe_closure(sig, cifframe_callback); - [b retain]; imp = [b executable]; #else imp = 0; @@ -640,7 +641,16 @@ - (void) overrideSetterFor: (NSString*)aKey } if (found == YES) { - [keys addObject: aKey]; + id info = nil; + +#if defined(USE_LIBFFI) + info = b; // Need to safe the code buffer +#endif + if (nil == info) + { + info = [NSNull null]; + } + [keys setObject: info forKey: aKey]; } else { @@ -648,15 +658,15 @@ - (void) overrideSetterFor: (NSString*)aKey if (depKeys) { - NSMapEnumerator enumerator = NSEnumerateMapTable(depKeys); - NSString *mainKey; - NSHashTable *dependents; + NSMapEnumerator enumerator = NSEnumerateMapTable(depKeys); + NSString *mainKey; + NSHashTable *dependents; while (NSNextMapEnumeratorPair(&enumerator, (void **)(&mainKey), (void**)&dependents)) { - NSHashEnumerator dependentKeyEnum; - NSString *dependentKey; + NSHashEnumerator dependentKeyEnum; + NSString *dependentKey; if (!dependents) continue; dependentKeyEnum = NSEnumerateHashTable(dependents); @@ -667,7 +677,7 @@ - (void) overrideSetterFor: (NSString*)aKey { [self overrideSetterFor: mainKey]; // Mark the key as used - [keys addObject: aKey]; + [keys setObject: [NSNull null] forKey: aKey]; found = YES; } } @@ -1542,6 +1552,7 @@ - (void) addObserver: (NSObject*)anObserver { info = [[GSKVOInfo alloc] initWithInstance: self]; [self setObservationInfo: info]; + RELEASE(info); object_setClass(self, [r replacement]); } @@ -1591,7 +1602,6 @@ - (void) removeObserver: (NSObject*)anObserver forKeyPath: (NSString*)aPath * turn off key-value-observing for it. */ object_setClass(self, [self class]); - IF_NO_ARC(AUTORELEASE(info);) [self setObservationInfo: nil]; } if ([aPath rangeOfString:@"."].location != NSNotFound) @@ -1618,7 +1628,6 @@ - (void) removeObserver: (NSObject*)anObserver * turn off key-value-observing for it. */ object_setClass(self, [self class]); - IF_NO_GC(AUTORELEASE(info);) [self setObservationInfo: nil]; } [kvoLock unlock]; diff --git a/Tests/base/Functions/runtime.m b/Tests/base/Functions/runtime.m index 58a29d22c0..7e0fabcdd9 100644 --- a/Tests/base/Functions/runtime.m +++ b/Tests/base/Functions/runtime.m @@ -79,6 +79,7 @@ - (const char *) sel2 int main(int argc, char *argv[]) { + ENTER_POOL id obj; Class cls; Class meta; @@ -294,6 +295,7 @@ - (const char *) sel2 PASS([NSStringFromSelector(sel) isEqual: @"xxxyyy_odd_name_xxxyyy"], "NSStringFromSelector() works for existing selector"); + LEAVE_POOL return 0; } diff --git a/Tests/base/NSArray/general.m b/Tests/base/NSArray/general.m index bea0a5e7ee..22deaa4d5d 100644 --- a/Tests/base/NSArray/general.m +++ b/Tests/base/NSArray/general.m @@ -10,9 +10,9 @@ int main() val1 = @"Hello"; val2 = @"A Goodbye"; val3 = @"Testing all strings"; - vals1 = [[[NSArray arrayWithObject:val1] arrayByAddingObject:val2] retain]; - vals2 = [[vals1 arrayByAddingObject:val2] retain]; - vals3 = [[vals1 arrayByAddingObject:val3] retain]; + vals1 = [[NSArray arrayWithObject:val1] arrayByAddingObject:val2]; + vals2 = [vals1 arrayByAddingObject:val2]; + vals3 = [vals1 arrayByAddingObject:val3]; obj = [NSArray new]; arr = obj; diff --git a/Tests/base/NSAutoreleasePool/autorelease_eh.m b/Tests/base/NSAutoreleasePool/autorelease_eh.m index 87a9385fa6..20386baf81 100644 --- a/Tests/base/NSAutoreleasePool/autorelease_eh.m +++ b/Tests/base/NSAutoreleasePool/autorelease_eh.m @@ -45,11 +45,13 @@ - (void) exceptionThrowingMethod int main(int argc, char** argv) { - NSAutoreleasePool *pool = [NSAutoreleasePool new]; + ENTER_POOL TestClass *testClass = [[TestClass new] autorelease]; [testClass runTest]; - [pool release]; - PASS(1, "Destroying pools in the wrong order didn't break anything..."); + LEAVE_POOL + ENTER_POOL + PASS(1, "Destroying pools in the wrong order didn't break anything...") + LEAVE_POOL return 0; } diff --git a/Tests/base/NSData/general.m b/Tests/base/NSData/general.m index 7d136aec77..a9050cbb66 100644 --- a/Tests/base/NSData/general.m +++ b/Tests/base/NSData/general.m @@ -6,7 +6,7 @@ int main() { - NSAutoreleasePool *arp = [NSAutoreleasePool new]; + START_SET("basic") char *str1, *str2; NSData *data1, *data2; NSMutableData *mutable; @@ -70,12 +70,12 @@ int main() && [data2 bytes] == str1, "+dataWithBytesNoCopy:length:freeWhenDone: works") - [arp release]; arp = nil; + END_SET("basic") - { + START_SET("segault check") BOOL didNotSegfault = YES; PASS(didNotSegfault, "+dataWithBytesNoCopy:length:freeWhenDone:NO doesn't free memory"); - } + END_SET("segfault check") START_SET("deallocator blocks") @@ -133,6 +133,6 @@ int main() # else SKIP("No Blocks support in the compiler.") # endif - END_SET("deallocator blocks") + END_SET("deallocator blocks") return 0; } diff --git a/Tests/base/NSFileHandle/singleton.m b/Tests/base/NSFileHandle/singleton.m index ade40c8485..011334f838 100644 --- a/Tests/base/NSFileHandle/singleton.m +++ b/Tests/base/NSFileHandle/singleton.m @@ -5,7 +5,7 @@ int main(void) { - NSAutoreleasePool *p = [NSAutoreleasePool new]; + ENTER_POOL NSFileHandle *a; NSFileHandle *b; NSFileHandle *c; @@ -19,6 +19,6 @@ int main(void) PASS_EXCEPTION([b release], NSGenericException, "Cannot dealloc stdout"); PASS_EXCEPTION([c release], NSGenericException, "Cannot dealloc stderr"); - [p drain]; + LEAVE_POOL return 0; } diff --git a/Tests/base/NSFileManager/general.m b/Tests/base/NSFileManager/general.m index e47a21fdb1..c4aa36e662 100644 --- a/Tests/base/NSFileManager/general.m +++ b/Tests/base/NSFileManager/general.m @@ -186,6 +186,7 @@ int main() NSData *dat1 = [mgr contentsAtPath: @"NSFMFile"]; str2 = [[NSString alloc] initWithData: dat1 encoding: 1]; PASS([str1 isEqualToString: str2], "NSFileManager file contents match"); + DESTROY(str2); } [NSThread sleepForTimeInterval: 1.0]; // So date of file is clearly in past [handler reset]; @@ -198,6 +199,7 @@ int main() NSData *dat1 = [mgr contentsAtPath: @"NSFMCopy"]; str2 = [[NSString alloc] initWithData: dat1 encoding: 1]; PASS([str1 isEqual: str2],"NSFileManager copied file contents match"); + DESTROY(str2); } NSDictionary *oa = [mgr fileAttributesAtPath: @"NSFMFile" traverseLink: NO]; NSDictionary *na = [mgr fileAttributesAtPath: @"NSFMCopy" traverseLink: NO]; @@ -245,6 +247,7 @@ int main() NSData *dat1 = [mgr contentsAtPath: @"NSFMMove"]; str2 = [[NSString alloc] initWithData: dat1 encoding: 1]; PASS([str1 isEqualToString: str2],"NSFileManager moved file contents match") + DESTROY(str2); } PASS(![mgr copyPath: @"NSFMFile" diff --git a/Tests/base/NSIndexPath/general.m b/Tests/base/NSIndexPath/general.m index 1d1befb53b..cfb542e947 100644 --- a/Tests/base/NSIndexPath/general.m +++ b/Tests/base/NSIndexPath/general.m @@ -5,7 +5,7 @@ int main() { - NSAutoreleasePool *arp = [NSAutoreleasePool new]; + ENTER_POOL NSIndexPath *index1; NSIndexPath *index2; NSUInteger i0[2]; @@ -70,10 +70,11 @@ int main() PASS([index2 compare: index1] == NSOrderedDescending, "longer index2 comparison the other way works"); - [arp release]; arp = nil; - { + LEAVE_POOL + START_SET("segfault") BOOL didNotSegfault = YES; PASS(didNotSegfault, "+indexPathWithIndex: doesn't mess up memory"); - } + END_SET("segfault") + return 0; } diff --git a/Tests/base/NSObject/test00.m b/Tests/base/NSObject/test00.m index 7db3865aa5..2216dac00c 100644 --- a/Tests/base/NSObject/test00.m +++ b/Tests/base/NSObject/test00.m @@ -5,8 +5,10 @@ int main() { + ENTER_POOL Class theClass = NSClassFromString(@"NSObject"); PASS(theClass == [NSObject class], "'NSObject' %s","uses +class to return self"); + LEAVE_POOL return 0; } diff --git a/Tests/base/NSOperation/threads.m b/Tests/base/NSOperation/threads.m index d40e845e22..07ef7f1a01 100644 --- a/Tests/base/NSOperation/threads.m +++ b/Tests/base/NSOperation/threads.m @@ -124,8 +124,8 @@ @implementation OpOrder static NSMutableArray *list = nil; + (void) initialize { - lock = [NSLock new]; - list = [NSMutableArray new]; + if (nil == lock) lock = [NSLock new]; + if (nil == list) list = [NSMutableArray new]; } - (void) main { diff --git a/Tests/base/lsan.txt b/Tests/base/lsan.txt new file mode 100644 index 0000000000..ba6746a736 --- /dev/null +++ b/Tests/base/lsan.txt @@ -0,0 +1,2 @@ +leak:__objc_exec_class +leak:class_addMethod