mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +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
c019ce0f9e
commit
2c18a5ea43
6 changed files with 160 additions and 21 deletions
|
@ -4,10 +4,15 @@
|
||||||
worked as expected and moved getpwnam() call to where it works.
|
worked as expected and moved getpwnam() call to where it works.
|
||||||
* Source/Additions/GSMime.m: ([GSMimeDocument-rawMimeData:]) bugfix
|
* Source/Additions/GSMime.m: ([GSMimeDocument-rawMimeData:]) bugfix
|
||||||
to remove mjime version header from inner documents.
|
to remove mjime version header from inner documents.
|
||||||
|
* Source/NSDebug.m: Additional functions for tracking memory problems.
|
||||||
* Source/NSBundle.m: Fixup for windows.
|
* Source/NSBundle.m: Fixup for windows.
|
||||||
* Source/NSFileManager.m: Fixup for windows.
|
* Source/NSFileManager.m: Fixup for windows.
|
||||||
* Source/NSString.m: Fixup for windows.
|
* Source/NSString.m: Fixup for windows.
|
||||||
Windows fixups adapted from patch by <Roland.Schwingel@onevision.de>
|
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>
|
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);
|
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
|
* Used to produce a format string for logging a message with function
|
||||||
* location details.
|
* location details.
|
||||||
|
@ -288,6 +298,29 @@ GS_EXPORT BOOL NSDeallocateZombies;
|
||||||
NSString *fmt = GSDebugMethodMsg( \
|
NSString *fmt = GSDebugMethodMsg( \
|
||||||
self, _cmd, __FILE__, __LINE__, format); \
|
self, _cmd, __FILE__, __LINE__, format); \
|
||||||
NSLog(fmt , ## args); }} while (0)
|
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
|
#else
|
||||||
#define NSDebugLLog(level, format, args...)
|
#define NSDebugLLog(level, format, args...)
|
||||||
#define NSDebugLog(format, args...)
|
#define NSDebugLog(format, args...)
|
||||||
|
@ -295,6 +328,8 @@ GS_EXPORT BOOL NSDeallocateZombies;
|
||||||
#define NSDebugFLog(format, args...)
|
#define NSDebugFLog(format, args...)
|
||||||
#define NSDebugMLLog(level, format, args...)
|
#define NSDebugMLLog(level, format, args...)
|
||||||
#define NSDebugMLog(format, args...)
|
#define NSDebugMLog(format, args...)
|
||||||
|
#define NSDebugFRLog(object, msg)
|
||||||
|
#define NSDebugMRLog(object, msg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -552,12 +552,19 @@ static SEL rlSel;
|
||||||
[aCoder decodeArrayOfObjCType: @encode(id)
|
[aCoder decodeArrayOfObjCType: @encode(id)
|
||||||
count: count
|
count: count
|
||||||
at: contents];
|
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
|
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)
|
while (j-- > 1)
|
||||||
{
|
{
|
||||||
(*addImp)(self, @selector(addObject:), objs[i]);
|
(*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 */
|
/* The following are used to record actual objects */
|
||||||
BOOL is_recording;
|
BOOL is_recording;
|
||||||
id *recorded_objects;
|
id *recorded_objects;
|
||||||
|
id *recorded_tags;
|
||||||
unsigned int num_recorded_objects;
|
unsigned int num_recorded_objects;
|
||||||
unsigned int stack_size;
|
unsigned int stack_size;
|
||||||
} table_entry;
|
} table_entry;
|
||||||
|
@ -178,6 +179,7 @@ GSDebugAllocationActiveRecordingObjects(Class c)
|
||||||
the_table[num_classes].peak = 0;
|
the_table[num_classes].peak = 0;
|
||||||
the_table[num_classes].is_recording = YES;
|
the_table[num_classes].is_recording = YES;
|
||||||
the_table[num_classes].recorded_objects = NULL;
|
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].num_recorded_objects = 0;
|
||||||
the_table[num_classes].stack_size = 0;
|
the_table[num_classes].stack_size = 0;
|
||||||
num_classes++;
|
num_classes++;
|
||||||
|
@ -206,21 +208,33 @@ GSDebugAllocationAdd(Class c, id o)
|
||||||
}
|
}
|
||||||
if (the_table[i].is_recording == YES)
|
if (the_table[i].is_recording == YES)
|
||||||
{
|
{
|
||||||
if (the_table[i].num_recorded_objects >=
|
if (the_table[i].num_recorded_objects
|
||||||
the_table[i].stack_size)
|
>= the_table[i].stack_size)
|
||||||
{
|
{
|
||||||
int more = the_table[i].stack_size + 128;
|
int more = the_table[i].stack_size + 128;
|
||||||
id *tmp;
|
id *tmp;
|
||||||
|
id *tmp1;
|
||||||
|
|
||||||
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
||||||
more * sizeof(id));
|
more * sizeof(id));
|
||||||
|
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
{
|
{
|
||||||
if (uniqueLock != nil)
|
if (uniqueLock != nil)
|
||||||
[uniqueLock unlock];
|
[uniqueLock unlock];
|
||||||
return;
|
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)
|
if (the_table[i].recorded_objects != NULL)
|
||||||
{
|
{
|
||||||
memcpy(tmp, the_table[i].recorded_objects,
|
memcpy(tmp, the_table[i].recorded_objects,
|
||||||
|
@ -228,13 +242,21 @@ GSDebugAllocationAdd(Class c, id o)
|
||||||
* sizeof(id));
|
* sizeof(id));
|
||||||
NSZoneFree(NSDefaultMallocZone(),
|
NSZoneFree(NSDefaultMallocZone(),
|
||||||
the_table[i].recorded_objects);
|
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_objects = tmp;
|
||||||
|
the_table[i].recorded_tags = tmp1;
|
||||||
the_table[i].stack_size = more;
|
the_table[i].stack_size = more;
|
||||||
}
|
}
|
||||||
|
|
||||||
(the_table[i].recorded_objects)
|
(the_table[i].recorded_objects)
|
||||||
[the_table[i].num_recorded_objects] = o;
|
[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++;
|
the_table[i].num_recorded_objects++;
|
||||||
}
|
}
|
||||||
if (uniqueLock != nil)
|
if (uniqueLock != nil)
|
||||||
|
@ -272,6 +294,7 @@ GSDebugAllocationAdd(Class c, id o)
|
||||||
the_table[num_classes].peak = 1;
|
the_table[num_classes].peak = 1;
|
||||||
the_table[num_classes].is_recording = NO;
|
the_table[num_classes].is_recording = NO;
|
||||||
the_table[num_classes].recorded_objects = NULL;
|
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].num_recorded_objects = 0;
|
||||||
the_table[num_classes].stack_size = 0;
|
the_table[num_classes].stack_size = 0;
|
||||||
num_classes++;
|
num_classes++;
|
||||||
|
@ -605,6 +628,8 @@ GSDebugAllocationRemove(Class c, id o)
|
||||||
{
|
{
|
||||||
if (the_table[i].class == c)
|
if (the_table[i].class == c)
|
||||||
{
|
{
|
||||||
|
id tag = nil;
|
||||||
|
|
||||||
if (uniqueLock != nil)
|
if (uniqueLock != nil)
|
||||||
[uniqueLock lock];
|
[uniqueLock lock];
|
||||||
the_table[i].count--;
|
the_table[i].count--;
|
||||||
|
@ -616,6 +641,7 @@ GSDebugAllocationRemove(Class c, id o)
|
||||||
{
|
{
|
||||||
if ((the_table[i].recorded_objects)[j] == o)
|
if ((the_table[i].recorded_objects)[j] == o)
|
||||||
{
|
{
|
||||||
|
tag = (the_table[i].recorded_tags)[j];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -627,6 +653,8 @@ GSDebugAllocationRemove(Class c, id o)
|
||||||
{
|
{
|
||||||
(the_table[i].recorded_objects)[k] =
|
(the_table[i].recorded_objects)[k] =
|
||||||
(the_table[i].recorded_objects)[k + 1];
|
(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--;
|
the_table[i].num_recorded_objects--;
|
||||||
}
|
}
|
||||||
|
@ -640,12 +668,67 @@ GSDebugAllocationRemove(Class c, id o)
|
||||||
}
|
}
|
||||||
if (uniqueLock != nil)
|
if (uniqueLock != nil)
|
||||||
[uniqueLock unlock];
|
[uniqueLock unlock];
|
||||||
|
RELEASE(tag);
|
||||||
return;
|
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
|
* This function returns an array
|
||||||
* containing all the allocated objects of a certain class
|
* containing all the allocated objects of a certain class
|
||||||
|
@ -702,7 +785,6 @@ GSDebugAllocationListRecordedObjects(Class c)
|
||||||
|
|
||||||
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
||||||
the_table[i].num_recorded_objects * sizeof(id));
|
the_table[i].num_recorded_objects * sizeof(id));
|
||||||
|
|
||||||
if (tmp == 0)
|
if (tmp == 0)
|
||||||
{
|
{
|
||||||
if (uniqueLock != nil)
|
if (uniqueLock != nil)
|
||||||
|
@ -714,10 +796,6 @@ GSDebugAllocationListRecordedObjects(Class c)
|
||||||
memcpy(tmp, the_table[i].recorded_objects,
|
memcpy(tmp, the_table[i].recorded_objects,
|
||||||
the_table[i].num_recorded_objects * sizeof(id));
|
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
|
/* Retain all the objects - NB: if retaining one of the objects as a
|
||||||
side effect releases another one of them , we are broken ... */
|
side effect releases another one of them , we are broken ... */
|
||||||
for (k = 0; k < the_table[i].num_recorded_objects; k++)
|
for (k = 0; k < the_table[i].num_recorded_objects; k++)
|
||||||
|
@ -725,6 +803,10 @@ GSDebugAllocationListRecordedObjects(Class c)
|
||||||
RETAIN (tmp[k]);
|
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
|
/* Only then we create an array with them - this is now safe as we
|
||||||
have copied the objects out, unlocked, and retained them. */
|
have copied the objects out, unlocked, and retained them. */
|
||||||
answer = [NSArray arrayWithObjects: tmp
|
answer = [NSArray arrayWithObjects: tmp
|
||||||
|
|
|
@ -166,17 +166,26 @@ static Class NSMutableSet_concrete_class;
|
||||||
self = [NSMutableSet_concrete_class allocWithZone: NSDefaultMallocZone()];
|
self = [NSMutableSet_concrete_class allocWithZone: NSDefaultMallocZone()];
|
||||||
return [self initWithCoder: aCoder];
|
return [self initWithCoder: aCoder];
|
||||||
}
|
}
|
||||||
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &count];
|
|
||||||
{
|
|
||||||
id objs[count];
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++)
|
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &count];
|
||||||
{
|
if (count > 0)
|
||||||
[aCoder decodeValueOfObjCType: @encode(id) at: &objs[i]];
|
{
|
||||||
}
|
id objs[count];
|
||||||
return [self initWithObjects: objs count: 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 />
|
/* <init />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue