Skip to content

Commit

Permalink
Merge branch 'atexit'
Browse files Browse the repository at this point in the history
  • Loading branch information
rfm committed Nov 19, 2024
2 parents eb0fc1a + e7e7051 commit 04902ba
Show file tree
Hide file tree
Showing 140 changed files with 1,744 additions and 1,278 deletions.
27 changes: 27 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
2024-11-19 Richard Frith-Macdonald <rfm@gnu.org>

* GSMime: fixed buffer overrun in rare circumstances when decoding
an encoded word in a header.
fix to cope with dealloc of uninitialised instances of GSMimeSMTPClient
* GSTLS: clean up used resources on exit
* NSCharacterSet: Fix retain count of cached character sets
* NSDateFormatter: fix to cope with dealloc of uninitialised instances
* NSFileManager: fix leak of enumerator when enumerating files at
a directory specified by URL
* NSHTTPCookie: fix buffer overrun parsing cookie header fields
* NSInvocation: fix leak of type information memory when passing
general struct argument/return values
* NSNumberFormatter: fix to cope with dealloc of uninitialised instances
* NSOperation: fix to cope with dealloc of uninitialised instances
* NSPredicate: fix leaks of keypath and set expressions
also fix leak of objects if exception occurs while scanning predicate
string
* NSPropertyList: fix leaks if exception occurs while parsing
* NSRegularExpression: fix leaks if exception occurs while parsing
* NSString: fix lead in dataUsingEncoding:allowLossyConversion:
* NSTimeZone: fix retain cycle in absolute time zones
fix leak of ICU calendar in -localizedName:locale:
* NSURL: fix leaks when initialising with unparseable string etc
* Testcases: fix many leaks so that most tests run to completion
without any leaked memory.

2024-11-14 Richard Frith-Macdonald <rfm@gnu.org>

* Source/NSBundle.m: Restructure a bit to expose resource lookup
Expand Down
46 changes: 26 additions & 20 deletions Headers/GNUstepBase/NSObject+GNUstepBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,16 +219,17 @@ extern "C" {
* set to YES).<br />
* Your class then has two options for performing clean-up when the process
* ends:
* <p>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 clean-up setting in force. This mechanism is simple
* and should be sufficient for many classes.
* <p>1. Use the +keep:at: method to register static/global variables whose
* contents are to be retained for the lifetime of the program (up to exit)
* and either ignored or released depending on the clean-up setting in force
* when the program exits.<br />
* This mechanism is simple and should be sufficient for many classes.
* </p>
* <p>2. Implement a +atExit method to be run when the process ends and,
* within your +initialize implementation, call +shouldCleanUp to determine
* whether clean-up should be done, and if it returns YES then call
* +registerAtExit to have your +atExit method called when the process
* terminates.
* <p>2. Implement an +atExit method to be run when the process ends and,
* within your +initialize implementation, +registerAtExit to have your
* +atExit method called when the process exits. Within the +atExit method
* you may call +shouldCleanUp to determine whether celan up has been
* requested.
* </p>
* <p>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
Expand All @@ -241,25 +242,30 @@ extern "C" {
*/
+ (BOOL) isExiting;

/** 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.
/** This method stores anObject at anAddress (which should be a static or
* global variable) and retains it. The code notes that the object should
* persist until the process exits. If clean-up is enabled the object will
* be released (and the address content zeroed out) upon process exit.
* If this method is called while the process is already exiting it
* simply zeros out the memory location then returns nil, otherwise
* it returns the object stored at the memory location.
* Raises an exception if anObject is nil or anAddress is NULL or the old
* value at anAddresss is not nil (unless the process is already exiting).
*/
+ (void) leaked: (id*)anAddress;
+ (id) NS_RETURNS_RETAINED keep: (id)anObject at: (id*)anAddress;

/** Deprecated: use +leaked: instead.
/** DEPRECATED ... use +keep:at: instead.
*/
+ (id) NS_RETURNS_RETAINED leak: (id)anObject ;//GS_DEPRECATED_FUNC;
+ (id) NS_RETURNS_RETAINED leak: (id)anObject;

/** Deprecated: use +leaked: instead.
/** DEPRECATED ... use +keep:at: instead.
*/
+ (id) NS_RETURNS_RETAINED leakAt: (id*)anAddress ;//GS_DEPRECATED_FUNC;
+ (id) NS_RETURNS_RETAINED leakAt: (id*)anAddress;

/** Sets the receiver to have its +atExit method called at the point when
* the process terminates.<br />
* Returns YES on success and NO on failure (if the class does not implement
* the method or if it is already registered to call it).<br />
* +atExit or if it is already registered to call it).<br />
* Implemented as a call to +registerAtExit: with the selector for the +atExit
* method as its argument.
*/
Expand All @@ -268,7 +274,7 @@ extern "C" {
/** Sets the receiver to have the specified method called at the point when
* the process terminates.<br />
* Returns YES on success and NO on failure (if the class does not implement
* the method ir if it is already registered to call it).
* the method or if it is already registered to call a method at exit).
*/
+ (BOOL) registerAtExit: (SEL)aSelector;

Expand Down
4 changes: 2 additions & 2 deletions Source/Additions/GSMime.m
Original file line number Diff line number Diff line change
Expand Up @@ -3045,7 +3045,7 @@ - (NSString*) _decodeHeader
*/
if (tmp > src)
{
unsigned char buf[tmp - src];
unsigned char buf[tmp - src + 1];
unsigned char *ptr;

ptr = decodeWord(buf, src, tmp, encoding);
Expand Down Expand Up @@ -8440,7 +8440,7 @@ - (void) abort
- (void) dealloc
{
[self abort];
if (internal != nil)
if (GS_EXISTS_INTERNAL)
{
DESTROY(internal->reply);
DESTROY(internal->wdata);
Expand Down
106 changes: 89 additions & 17 deletions Source/Additions/NSObject+GNUstepBase.m
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,12 @@ static inline void setup()
BOOL unknownThread;

isExiting = YES;
/* We turn off zombies during exiting so that we don't leak deallocated
* objects during cleanup.
*/
// NSZombieEnabled = NO;
unknownThread = GSRegisterCurrentThread();
CREATE_AUTORELEASE_POOL(arp);
ENTER_POOL

while (exited != 0)
{
Expand All @@ -193,25 +197,40 @@ static inline void setup()
Method method;
IMP msg;

if (shouldCleanUp)
{
fprintf(stderr, "*** clean-up +[%s %s]\n",
class_getName(tmp->obj), sel_getName(tmp->sel));
}
method = class_getClassMethod(tmp->obj, tmp->sel);
msg = method_getImplementation(method);
if (0 != msg)
{
(*msg)(tmp->obj, tmp->sel);
}
}
else if (YES == shouldCleanUp)
else if (shouldCleanUp)
{
if (0 != tmp->at)
if (tmp->at)
{
tmp->obj = *(tmp->at);
if (tmp->obj != *(tmp->at))
{
fprintf(stderr,
"*** clean-up kept value %p at %p changed to %p\n",
tmp->obj, (const void*)tmp->at, *(tmp->at));
tmp->obj = *(tmp->at);
}
*(tmp->at) = nil;
}
fprintf(stderr, "*** clean-up -[%s release] %p %p\n",
class_getName(object_getClass(tmp->obj)),
tmp->obj, (const void*)tmp->at);
[tmp->obj release];
}
free(tmp);
}
DESTROY(arp);
LEAVE_POOL

if (unknownThread == YES)
{
GSUnregisterCurrentThread();
Expand All @@ -226,26 +245,54 @@ + (BOOL) isExiting
return isExiting;
}

+ (void) leaked: (id*)anAddress
+ (id) keep: (id)anObject at: (id*)anAddress
{
struct exitLink *l;

NSAssert(*anAddress && [*anAddress isKindOfClass: [NSObject class]],
if (isExiting)
{
if (anAddress)
{
[*anAddress release];
*anAddress = nil;
}
return nil;
}
NSAssert([anObject isKindOfClass: [NSObject class]],
NSInvalidArgumentException);
NSAssert(anAddress != NULL, NSInvalidArgumentException);
NSAssert(*anAddress == nil, NSInvalidArgumentException);
setup();
[exitLock lock];
for (l = exited; l != NULL; l = l->next)
{
if (l->at == anAddress)
{
[exitLock unlock];
[NSException raise: NSInvalidArgumentException
format: @"Repeated use of leak address %p", anAddress];
}
if (anObject != nil && anObject == l->obj)
{
[exitLock unlock];
[NSException raise: NSInvalidArgumentException
format: @"Repeated use of leak object %p", anObject];
}
}
ASSIGN(*anAddress, anObject);
l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->at = anAddress;
l->obj = *anAddress;
l->obj = anObject;
l->sel = 0;
setup();
[exitLock lock];
l->next = exited;
exited = l;
[exitLock unlock];
return l->obj;
}

+ (id) leakAt: (id*)anAddress
{
struct exitLink *l;
struct exitLink *l;

l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->at = anAddress;
Expand All @@ -263,12 +310,25 @@ + (id) leak: (id)anObject
{
struct exitLink *l;

if (nil == anObject || isExiting)
{
return nil;
}
setup();
[exitLock lock];
for (l = exited; l != NULL; l = l->next)
{
if (l->obj == anObject || (l->at != NULL && *l->at == anObject))
{
[exitLock unlock];
[NSException raise: NSInvalidArgumentException
format: @"Repeated use of leak object %p", anObject];
}
}
l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->at = 0;
l->obj = [anObject retain];
l->sel = 0;
setup();
[exitLock lock];
l->next = exited;
exited = l;
[exitLock unlock];
Expand Down Expand Up @@ -307,10 +367,16 @@ + (BOOL) registerAtExit: (SEL)sel
[exitLock lock];
for (l = exited; l != 0; l = l->next)
{
if (l->obj == self && sel_isEqual(l->sel, sel))
if (l->obj == self)
{
[exitLock unlock];
return NO; // Already registered
if (sel_isEqual(l->sel, sel))
{
fprintf(stderr,
"*** +[%s registerAtExit: %s] already registered for %s.\n",
class_getName(self), sel_getName(sel), sel_getName(l->sel));
[exitLock unlock];
return NO; // Already registered
}
}
}
l = (struct exitLink*)malloc(sizeof(struct exitLink));
Expand Down Expand Up @@ -463,7 +529,13 @@ - (NSUInteger) sizeOfInstance

/* Dummy implementation
*/
@implementation NSObject(GSCleanup)
@implementation NSObject(GSCleanUp)

+ (id) keep: (id)anObject at: (id*)anAddress
{
ASSIGN(*anAddress, anObject);
return *anAddress;
}

+ (id) leakAt: (id*)anAddress
{
Expand Down
3 changes: 1 addition & 2 deletions Source/GSFFIInvocation.m
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,7 @@ - (id) initWithMethodSignature: (NSMethodSignature*)aSignature
_sig = RETAIN(aSignature);
_numArgs = [aSignature numberOfArguments];
_info = [aSignature methodInfo];
_frame = cifframe_from_signature(_sig);
[_frame retain];
[self setupFrameFFI: _sig];
_cframe = [_frame mutableBytes];

/* Make sure we have somewhere to store the return value if needed.
Expand Down
2 changes: 1 addition & 1 deletion Source/GSFormat.m
Original file line number Diff line number Diff line change
Expand Up @@ -1770,7 +1770,7 @@ static int printf_unknown (GSStr, const struct printf_info *,

if (-1 == prec)
{
len = strlen(str); // Number of bytes to convert.
len = strlen(str); // Number of bytes to convert.
blen = len; // Size of unichar output buffer.
}
else
Expand Down
11 changes: 8 additions & 3 deletions Source/GSInvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#import "Foundation/NSInvocation.h"

@class NSMutableData;
@class NSPointerArray;

typedef struct {
int offset;
Expand All @@ -39,13 +40,17 @@ typedef struct {
} NSArgumentInfo;


@interface GSFFIInvocation : NSInvocation
@interface GSFFIInvocation : NSInvocation
{
@public
uint8_t _retbuf[32]; // Store return values of up to 32 bytes here.
NSMutableData *_frame;
uint8_t _retbuf[32]; // Return values of up to 32 bytes here.
NSMutableData *_frame; // Frame information for invoking.
NSPointerArray *_extra; // Extra FFI data to be released.
}
@end
@interface GSFFIInvocation (FFI)
- (void) setupFrameFFI: (NSMethodSignature*)sig;
@end

@interface GSFFCallInvocation : NSInvocation
{
Expand Down
Loading

0 comments on commit 04902ba

Please sign in to comment.