mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
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:
parent
1c51fc5389
commit
7a9e11fdbf
6 changed files with 160 additions and 21 deletions
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -152,6 +152,7 @@ static Class NSCountedSet_concrete_class;
|
|||
while (j-- > 1)
|
||||
{
|
||||
(*addImp)(self, @selector(addObject:), objs[i]);
|
||||
RELEASE(objs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
100
Source/NSDebug.m
100
Source/NSDebug.m
|
@ -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
|
||||
|
|
|
@ -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 />
|
||||
|
|
Loading…
Reference in a new issue