Memory leak fixes and a little new debug functionality

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@17803 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2003-10-08 15:03:58 +00:00
parent 1c51fc5389
commit 7a9e11fdbf
6 changed files with 160 additions and 21 deletions

View file

@ -4,10 +4,15 @@
worked as expected and moved getpwnam() call to where it works.
* Source/Additions/GSMime.m: ([GSMimeDocument-rawMimeData:]) bugfix
to remove mjime version header from inner documents.
* Source/NSDebug.m: Additional functions for tracking memory problems.
* Source/NSBundle.m: Fixup for windows.
* Source/NSFileManager.m: Fixup for windows.
* Source/NSString.m: Fixup for windows.
Windows fixups adapted from patch by <Roland.Schwingel@onevision.de>
* Source/NSArray.m: Fix memory leak initialising from coder.
* Source/NSCountedSet.m: ditto
* Source/NSSet.m: ditto
Memory leak fixes adapted from patch by <Roland.Schwingel@onevision.de>
2003-10-07 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -132,6 +132,16 @@ GS_EXPORT void GSDebugAllocationActiveRecordingObjects(Class c);
*/
GS_EXPORT NSArray *GSDebugAllocationListRecordedObjects(Class c);
/**
* This function associates the supplied tag with a recorded
* object and returns the tag which was previously associated
* with it (if any).<br />
* If the object was not recorded, the method reurns nil<br />
* The tag is retained while it is associated with the object.<br />
* See also the NSDebugFRLog() and NSDebugMRLog() macros.
*/
GS_EXPORT id GSDebugAllocationTagRecordedObject(id object, id tag);
/**
* Used to produce a format string for logging a message with function
* location details.
@ -288,6 +298,29 @@ GS_EXPORT BOOL NSDeallocateZombies;
NSString *fmt = GSDebugMethodMsg( \
self, _cmd, __FILE__, __LINE__, format); \
NSLog(fmt , ## args); }} while (0)
/**
* This macro saves the name and location of the function in
* which the macro is used, along with a short string msg as
* the tag associated with a recorded object.
*/
#define NSDebugFRLog(object, msg) \
do { \
NSString *tag = GSDebugFunctionMsg( \
__PRETTY_FUNCTION__, __FILE__, __LINE__, msg); \
GSDebugAllocationTagRecordedObject(object, tag); } while (0)
/**
* This macro saves the name and location of the method in
* which the macro is used, along with a short string msg as
* the tag associated with a recorded object.
*/
#define NSDebugMRLog(object, msg) \
do { \
NSString *tag = GSDebugMethodMsg( \
self, _cmd, __FILE__, __LINE__, msg); \
GSDebugAllocationTagRecordedObject(object, tag); } while (0)
#else
#define NSDebugLLog(level, format, args...)
#define NSDebugLog(format, args...)
@ -295,6 +328,8 @@ GS_EXPORT BOOL NSDeallocateZombies;
#define NSDebugFLog(format, args...)
#define NSDebugMLLog(level, format, args...)
#define NSDebugMLog(format, args...)
#define NSDebugFRLog(object, msg)
#define NSDebugMRLog(object, msg)
#endif

View file

@ -552,12 +552,19 @@ static SEL rlSel;
[aCoder decodeArrayOfObjCType: @encode(id)
count: count
at: contents];
return [self initWithObjects: contents count: count];
self = [self initWithObjects: contents count: count];
#if GS_WITH_GC == 0
while (count-- > 0)
{
[contents[count] release];
}
#endif
}
else
{
return [self initWithObjects: 0 count: 0];
self = [self initWithObjects: 0 count: 0];
}
return self;
}
/**

View file

@ -152,6 +152,7 @@ static Class NSCountedSet_concrete_class;
while (j-- > 1)
{
(*addImp)(self, @selector(addObject:), objs[i]);
RELEASE(objs[i]);
}
}
}

View file

@ -45,6 +45,7 @@ typedef struct {
/* The following are used to record actual objects */
BOOL is_recording;
id *recorded_objects;
id *recorded_tags;
unsigned int num_recorded_objects;
unsigned int stack_size;
} table_entry;
@ -178,6 +179,7 @@ GSDebugAllocationActiveRecordingObjects(Class c)
the_table[num_classes].peak = 0;
the_table[num_classes].is_recording = YES;
the_table[num_classes].recorded_objects = NULL;
the_table[num_classes].recorded_tags = NULL;
the_table[num_classes].num_recorded_objects = 0;
the_table[num_classes].stack_size = 0;
num_classes++;
@ -206,21 +208,33 @@ GSDebugAllocationAdd(Class c, id o)
}
if (the_table[i].is_recording == YES)
{
if (the_table[i].num_recorded_objects >=
the_table[i].stack_size)
if (the_table[i].num_recorded_objects
>= the_table[i].stack_size)
{
int more = the_table[i].stack_size + 128;
int more = the_table[i].stack_size + 128;
id *tmp;
id *tmp1;
tmp = NSZoneMalloc(NSDefaultMallocZone(),
more * sizeof(id));
if (tmp == 0)
{
if (uniqueLock != nil)
[uniqueLock unlock];
return;
}
tmp1 = NSZoneMalloc(NSDefaultMallocZone(),
more * sizeof(id));
if (tmp1 == 0)
{
NSZoneFree(NSDefaultMallocZone(), tmp);
if (uniqueLock != nil)
[uniqueLock unlock];
return;
}
if (the_table[i].recorded_objects != NULL)
{
memcpy(tmp, the_table[i].recorded_objects,
@ -228,13 +242,21 @@ GSDebugAllocationAdd(Class c, id o)
* sizeof(id));
NSZoneFree(NSDefaultMallocZone(),
the_table[i].recorded_objects);
memcpy(tmp1, the_table[i].recorded_tags,
the_table[i].num_recorded_objects
* sizeof(id));
NSZoneFree(NSDefaultMallocZone(),
the_table[i].recorded_tags);
}
the_table[i].recorded_objects = tmp;
the_table[i].recorded_tags = tmp1;
the_table[i].stack_size = more;
}
(the_table[i].recorded_objects)
[the_table[i].num_recorded_objects] = o;
(the_table[i].recorded_tags)
[the_table[i].num_recorded_objects] = nil;
the_table[i].num_recorded_objects++;
}
if (uniqueLock != nil)
@ -272,6 +294,7 @@ GSDebugAllocationAdd(Class c, id o)
the_table[num_classes].peak = 1;
the_table[num_classes].is_recording = NO;
the_table[num_classes].recorded_objects = NULL;
the_table[num_classes].recorded_tags = NULL;
the_table[num_classes].num_recorded_objects = 0;
the_table[num_classes].stack_size = 0;
num_classes++;
@ -605,6 +628,8 @@ GSDebugAllocationRemove(Class c, id o)
{
if (the_table[i].class == c)
{
id tag = nil;
if (uniqueLock != nil)
[uniqueLock lock];
the_table[i].count--;
@ -616,6 +641,7 @@ GSDebugAllocationRemove(Class c, id o)
{
if ((the_table[i].recorded_objects)[j] == o)
{
tag = (the_table[i].recorded_tags)[j];
break;
}
}
@ -627,6 +653,8 @@ GSDebugAllocationRemove(Class c, id o)
{
(the_table[i].recorded_objects)[k] =
(the_table[i].recorded_objects)[k + 1];
(the_table[i].recorded_tags)[k] =
(the_table[i].recorded_tags)[k + 1];
}
the_table[i].num_recorded_objects--;
}
@ -640,12 +668,67 @@ GSDebugAllocationRemove(Class c, id o)
}
if (uniqueLock != nil)
[uniqueLock unlock];
RELEASE(tag);
return;
}
}
}
}
/**
* This function associates the supplied tag with a recorded
* object and returns the tag which was previously associated
* with it (if any).<br />
* If the object was not recorded, the method returns nil<br />
* The tag is retained while it is associated with the object.
*/
id
GSDebugAllocationTagRecordedObject(id object, id tag)
{
Class c = [object class];
id o = nil;
int i;
int j;
if (debug_allocation == NO)
{
return nil;
}
if (uniqueLock != nil)
[uniqueLock lock];
for (i = 0; i < num_classes; i++)
{
if (the_table[i].class == c)
{
break;
}
}
if (i == num_classes
|| the_table[i].is_recording == NO
|| the_table[i].num_recorded_objects == 0)
{
if (uniqueLock != nil)
[uniqueLock unlock];
return nil;
}
for (j = 0; j < the_table[i].num_recorded_objects; j++)
{
if (the_table[i].recorded_objects[j] == object)
{
o = the_table[i].recorded_tags[j];
the_table[i].recorded_tags[j] = RETAIN(tag);
break;
}
}
if (uniqueLock != nil)
[uniqueLock unlock];
return AUTORELEASE(o);
}
/**
* This function returns an array
* containing all the allocated objects of a certain class
@ -702,7 +785,6 @@ GSDebugAllocationListRecordedObjects(Class c)
tmp = NSZoneMalloc(NSDefaultMallocZone(),
the_table[i].num_recorded_objects * sizeof(id));
if (tmp == 0)
{
if (uniqueLock != nil)
@ -714,10 +796,6 @@ GSDebugAllocationListRecordedObjects(Class c)
memcpy(tmp, the_table[i].recorded_objects,
the_table[i].num_recorded_objects * sizeof(id));
/* Then, we bravely unlock the lock */
if (uniqueLock != nil)
[uniqueLock unlock];
/* Retain all the objects - NB: if retaining one of the objects as a
side effect releases another one of them , we are broken ... */
for (k = 0; k < the_table[i].num_recorded_objects; k++)
@ -725,6 +803,10 @@ GSDebugAllocationListRecordedObjects(Class c)
RETAIN (tmp[k]);
}
/* Then, we bravely unlock the lock */
if (uniqueLock != nil)
[uniqueLock unlock];
/* Only then we create an array with them - this is now safe as we
have copied the objects out, unlocked, and retained them. */
answer = [NSArray arrayWithObjects: tmp

View file

@ -166,17 +166,26 @@ static Class NSMutableSet_concrete_class;
self = [NSMutableSet_concrete_class allocWithZone: NSDefaultMallocZone()];
return [self initWithCoder: aCoder];
}
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &count];
{
id objs[count];
unsigned i;
for (i = 0; i < count; i++)
{
[aCoder decodeValueOfObjCType: @encode(id) at: &objs[i]];
}
return [self initWithObjects: objs count: count];
}
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &count];
if (count > 0)
{
id objs[count];
unsigned i;
for (i = 0; i < count; i++)
{
[aCoder decodeValueOfObjCType: @encode(id) at: &objs[i]];
}
self = [self initWithObjects: objs count: count];
#if GS_WITH_GC == 0
while (count-- > 0)
{
[objs[count] release];
}
#endif
}
return self;
}
/* <init />