mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
Memory leaks in DO fixed.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@9557 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4fdda0532b
commit
1b04f169ea
5 changed files with 141 additions and 37 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2001-04-11 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/GSFFCallInvocation.m: bugfix encoding ... pass correct
|
||||
method type information so that the other end knows whether this
|
||||
is a oneway message or not. Corrects major memory leak.
|
||||
* Source/NSConnection.m: bugfix to handle situations where the
|
||||
other end sends a response and we are not expecting it. Also
|
||||
added various bits of debugging and ensured that all NSPortCoder
|
||||
objects are cached.
|
||||
|
||||
2001-04-10 Adam Fedor <fedor@gnu.org>
|
||||
|
||||
* Headers/gnustep/base/preface.h.in: Correct NeXT_RUNTIME name
|
||||
|
|
|
@ -581,8 +581,9 @@ void GSInvocationCallback(void *callback_data, va_alist args)
|
|||
{
|
||||
int i;
|
||||
BOOL out_parameters = NO;
|
||||
const char *type = [_sig methodType];
|
||||
|
||||
[coder encodeValueOfObjCType: @encode(char*) at: &_info[0].type];
|
||||
[coder encodeValueOfObjCType: @encode(char*) at: &type];
|
||||
|
||||
for (i = 0; i < _numArgs; i++)
|
||||
{
|
||||
|
|
|
@ -34,10 +34,10 @@
|
|||
/* Key for thread dictionary. */
|
||||
static NSString *dict_key = @"_NSAssertionHandler";
|
||||
|
||||
+ (NSAssertionHandler*)currentHandler
|
||||
+ (NSAssertionHandler*) currentHandler
|
||||
{
|
||||
NSMutableDictionary *dict;
|
||||
NSAssertionHandler *handler;
|
||||
NSMutableDictionary *dict;
|
||||
NSAssertionHandler *handler;
|
||||
|
||||
dict = GSCurrentThreadDictionary();
|
||||
handler = [dict objectForKey: dict_key];
|
||||
|
@ -54,8 +54,8 @@ static NSString *dict_key = @"_NSAssertionHandler";
|
|||
lineNumber: (int)line
|
||||
description: (NSString*)format,...
|
||||
{
|
||||
id message;
|
||||
va_list ap;
|
||||
id message;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
message =
|
||||
|
@ -65,8 +65,8 @@ static NSString *dict_key = @"_NSAssertionHandler";
|
|||
NSLogv(message, ap);
|
||||
va_end(ap);
|
||||
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format: message arguments: ap];
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: message arguments: ap];
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
||||
|
@ -76,8 +76,8 @@ static NSString *dict_key = @"_NSAssertionHandler";
|
|||
lineNumber: (int) line
|
||||
description: (NSString *) format,...
|
||||
{
|
||||
id message;
|
||||
va_list ap;
|
||||
id message;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
message =
|
||||
|
@ -88,7 +88,7 @@ static NSString *dict_key = @"_NSAssertionHandler";
|
|||
NSLogv(message, ap);
|
||||
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: message arguments: ap];
|
||||
format: message arguments: ap];
|
||||
va_end(ap);
|
||||
/* NOT REACHED */
|
||||
}
|
||||
|
|
|
@ -92,7 +92,8 @@ static Class connectionClass;
|
|||
static Class dateClass;
|
||||
static Class distantObjectClass;
|
||||
static Class localCounterClass;
|
||||
static Class portCoderClass;
|
||||
static Class sendCoderClass;
|
||||
static Class recvCoderClass;
|
||||
static Class runLoopClass;
|
||||
|
||||
static NSString*
|
||||
|
@ -226,6 +227,8 @@ static unsigned local_object_counter = 0;
|
|||
- (void) removeLocalObject: (id)anObj;
|
||||
|
||||
- (void) _doneInRmc: (NSPortCoder*)c;
|
||||
- (void) _failInRmc: (NSPortCoder*)c;
|
||||
- (void) _failOutRmc: (NSPortCoder*)c;
|
||||
- (NSPortCoder*) _getReplyRmc: (int)sn;
|
||||
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components;
|
||||
- (NSPortCoder*) _makeOutRmc: (int)sequence generate: (int*)sno reply: (BOOL)f;
|
||||
|
@ -493,7 +496,8 @@ static BOOL multi_threaded = NO;
|
|||
dateClass = [NSDate class];
|
||||
distantObjectClass = [NSDistantObject class];
|
||||
localCounterClass = [GSLocalCounter class];
|
||||
portCoderClass = [NSPortCoder class];
|
||||
sendCoderClass = [NSPortCoder class];
|
||||
recvCoderClass = [NSPortCoder class];
|
||||
runLoopClass = [NSRunLoop class];
|
||||
|
||||
dummyObject = [NSObject new];
|
||||
|
@ -1206,7 +1210,7 @@ static BOOL multi_threaded = NO;
|
|||
|
||||
ip = [self _getReplyRmc: seq_num];
|
||||
[ip decodeValueOfObjCType: @encode(id) at: &newProxy];
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
return AUTORELEASE(newProxy);
|
||||
}
|
||||
|
||||
|
@ -1511,11 +1515,27 @@ static BOOL multi_threaded = NO;
|
|||
|
||||
if (needsResponse == NO)
|
||||
{
|
||||
GSIMapNode node;
|
||||
|
||||
/*
|
||||
* Since we don't need a response, we can remove the placeholder from
|
||||
* the _replyMap.
|
||||
* the _replyMap. However, in case the other end has already sent us
|
||||
* a response, we must check for it and scrap it if necessary.
|
||||
*/
|
||||
M_LOCK(_refGate);
|
||||
node = GSIMapNodeForKey(_replyMap, (GSIMapKey)seq_num);
|
||||
if (node != 0 && node->value.obj != dummyObject)
|
||||
{
|
||||
BOOL is_exception = NO;
|
||||
|
||||
[node->value.obj decodeValueOfObjCType: @encode(BOOL)
|
||||
at: &is_exception];
|
||||
if (is_exception == YES)
|
||||
NSLog(@"Got exception with %@", NSStringFromSelector(sel));
|
||||
else
|
||||
NSLog(@"Got response with %@", NSStringFromSelector(sel));
|
||||
[self _doneInRmc: node->value.obj];
|
||||
}
|
||||
GSIMapRemoveKey(_replyMap, (GSIMapKey)seq_num);
|
||||
M_UNLOCK(_refGate);
|
||||
retframe = alloca(sizeof(void*)); /* Dummy value for void return. */
|
||||
|
@ -1531,7 +1551,7 @@ static BOOL multi_threaded = NO;
|
|||
{
|
||||
if (ip != nil)
|
||||
{
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
/* this must be here to avoid trashing alloca'ed retframe */
|
||||
ip = (id)-1;
|
||||
_repInCount++; /* received a reply */
|
||||
|
@ -1539,9 +1559,9 @@ static BOOL multi_threaded = NO;
|
|||
return;
|
||||
}
|
||||
/* If we didn't get the reply packet yet, get it now. */
|
||||
if (!ip)
|
||||
if (ip == nil)
|
||||
{
|
||||
if (!_isValid)
|
||||
if (_isValid == NO)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"connection waiting for request was shut down"];
|
||||
|
@ -1552,12 +1572,12 @@ static BOOL multi_threaded = NO;
|
|||
* of the return values.
|
||||
*/
|
||||
[ip decodeValueOfObjCType: @encode(BOOL) at: &is_exception];
|
||||
if (is_exception)
|
||||
if (is_exception == YES)
|
||||
{
|
||||
/* Decode the exception object, and raise it. */
|
||||
id exc;
|
||||
[ip decodeValueOfObjCType: @encode(id) at: &exc];
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
ip = (id)-1;
|
||||
/* xxx Is there anything else to clean up in
|
||||
dissect_method_return()? */
|
||||
|
@ -1653,11 +1673,28 @@ static BOOL multi_threaded = NO;
|
|||
|
||||
if (needsResponse == NO)
|
||||
{
|
||||
GSIMapNode node;
|
||||
|
||||
/*
|
||||
* Since we don't need a response, we can remove the placeholder from
|
||||
* the _replyMap.
|
||||
* the _replyMap. However, in case the other end has already sent us
|
||||
* a response, we must check for it and scrap it if necessary.
|
||||
*/
|
||||
M_LOCK(_refGate);
|
||||
node = GSIMapNodeForKey(_replyMap, (GSIMapKey)seq_num);
|
||||
if (node != 0 && node->value.obj != dummyObject)
|
||||
{
|
||||
BOOL is_exception = NO;
|
||||
SEL sel = [inv selector];
|
||||
|
||||
[node->value.obj decodeValueOfObjCType: @encode(BOOL)
|
||||
at: &is_exception];
|
||||
if (is_exception == YES)
|
||||
NSLog(@"Got exception with %@", NSStringFromSelector(sel));
|
||||
else
|
||||
NSLog(@"Got response with %@", NSStringFromSelector(sel));
|
||||
[self _doneInRmc: node->value.obj];
|
||||
}
|
||||
GSIMapRemoveKey(_replyMap, (GSIMapKey)seq_num);
|
||||
M_UNLOCK(_refGate);
|
||||
}
|
||||
|
@ -1672,7 +1709,7 @@ static BOOL multi_threaded = NO;
|
|||
{
|
||||
if (ip != nil)
|
||||
{
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
/* this must be here to avoid trashing alloca'ed retframe */
|
||||
ip = (id)-1;
|
||||
_repInCount++; /* received a reply */
|
||||
|
@ -1680,9 +1717,9 @@ static BOOL multi_threaded = NO;
|
|||
return;
|
||||
}
|
||||
/* If we didn't get the reply packet yet, get it now. */
|
||||
if (!ip)
|
||||
if (ip == nil)
|
||||
{
|
||||
if (!_isValid)
|
||||
if (_isValid == NO)
|
||||
{
|
||||
[NSException raise: NSGenericException
|
||||
format: @"connection waiting for request was shut down"];
|
||||
|
@ -1693,12 +1730,12 @@ static BOOL multi_threaded = NO;
|
|||
* of the return values.
|
||||
*/
|
||||
[ip decodeValueOfObjCType: @encode(BOOL) at: &is_exception];
|
||||
if (is_exception)
|
||||
if (is_exception == YES)
|
||||
{
|
||||
/* Decode the exception object, and raise it. */
|
||||
id exc;
|
||||
[ip decodeValueOfObjCType: @encode(id) at: &exc];
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
ip = (id)-1;
|
||||
/* xxx Is there anything else to clean up in
|
||||
dissect_method_return()? */
|
||||
|
@ -1736,7 +1773,7 @@ static BOOL multi_threaded = NO;
|
|||
[self _sendOutRmc: op type: METHODTYPE_REQUEST];
|
||||
ip = [self _getReplyRmc: seq_num];
|
||||
[ip decodeValueOfObjCType: @encode(char*) at: &type];
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -1832,6 +1869,10 @@ static BOOL multi_threaded = NO;
|
|||
}
|
||||
|
||||
rmc = [conn _makeInRmc: components];
|
||||
if (debug_connection > 5)
|
||||
{
|
||||
NSLog(@"made rmc 0x%x for %d", rmc, type);
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
@ -1902,19 +1943,21 @@ static BOOL multi_threaded = NO;
|
|||
node = GSIMapNodeForKey(conn->_replyMap, (GSIMapKey)sequence);
|
||||
if (node == 0)
|
||||
{
|
||||
NSDebugMLLog(@"NSConnection", @"Ignoring RMC %d on %x",
|
||||
NSDebugMLLog(@"NSConnection", @"Ignoring reply RMC %d on %x",
|
||||
sequence, conn);
|
||||
RELEASE(rmc);
|
||||
[self _doneInRmc: rmc];
|
||||
}
|
||||
else if (node->value.obj == dummyObject)
|
||||
{
|
||||
NSDebugMLLog(@"NSConnection", @"Saving reply RMC %d on %x",
|
||||
sequence, conn);
|
||||
node->value.obj = rmc;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSDebugMLLog(@"NSConnection", @"Replace RMC %d on %x",
|
||||
NSDebugMLLog(@"NSConnection", @"Replace reply RMC %d on %x",
|
||||
sequence, conn);
|
||||
RELEASE(node->value.obj);
|
||||
[self _doneInRmc: node->value.obj];
|
||||
node->value.obj = rmc;
|
||||
}
|
||||
M_UNLOCK(conn->_queueGate);
|
||||
|
@ -1989,14 +2032,13 @@ static BOOL multi_threaded = NO;
|
|||
|
||||
void encoder (int argnum, void *datum, const char *type, int flags)
|
||||
{
|
||||
#define ENCODED_RETNAME @"return value"
|
||||
if (op == nil)
|
||||
{
|
||||
BOOL is_exception = NO;
|
||||
/* It is possible that our connection died while the method was
|
||||
being called - in this case we mustn't try to send the result
|
||||
back to the remote application! */
|
||||
if (!_isValid)
|
||||
if (_isValid == NO)
|
||||
return;
|
||||
op = [self _makeOutRmc: reply_sno generate: 0 reply: NO];
|
||||
[op encodeValueOfObjCType: @encode(BOOL) at: &is_exception];
|
||||
|
@ -2055,11 +2097,16 @@ static BOOL multi_threaded = NO;
|
|||
{
|
||||
BOOL is_exception = YES;
|
||||
|
||||
[self _failInRmc: aRmc];
|
||||
/* Send the exception back to the client. */
|
||||
if (_isValid)
|
||||
if (_isValid == YES)
|
||||
{
|
||||
NS_DURING
|
||||
{
|
||||
if (op != nil)
|
||||
{
|
||||
[self _failOutRmc: op];
|
||||
}
|
||||
op = [self _makeOutRmc: reply_sno generate: 0 reply: NO];
|
||||
[op encodeValueOfObjCType: @encode(BOOL)
|
||||
at: &is_exception];
|
||||
|
@ -2374,18 +2421,59 @@ static BOOL multi_threaded = NO;
|
|||
[NSException raise: NSPortTimeoutException
|
||||
format: @"timed out waiting for reply"];
|
||||
}
|
||||
NSDebugMLLog(@"NSConnection", @"Consuming reply RMC %d on %x", sn, self);
|
||||
return rmc;
|
||||
}
|
||||
|
||||
- (void) _doneInRmc: (NSPortCoder*)c
|
||||
{
|
||||
M_LOCK(_refGate);
|
||||
if (debug_connection > 5)
|
||||
{
|
||||
NSLog(@"done rmc 0x%x", c);
|
||||
}
|
||||
[_cachedDecoders addObject: c];
|
||||
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
||||
RELEASE(c);
|
||||
M_UNLOCK(_refGate);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method called if an exception occurred, and we don't know
|
||||
* whether we have already tidied the NSPortCoder object up or not.
|
||||
*/
|
||||
- (void) _failInRmc: (NSPortCoder*)c
|
||||
{
|
||||
M_LOCK(_refGate);
|
||||
if ([_cachedDecoders indexOfObjectIdenticalTo: c] == NSNotFound)
|
||||
{
|
||||
if (debug_connection > 5)
|
||||
{
|
||||
NSLog(@"fail rmc 0x%x", c);
|
||||
}
|
||||
[_cachedDecoders addObject: c];
|
||||
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
||||
RELEASE(c);
|
||||
}
|
||||
M_UNLOCK(_refGate);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method called if an exception occurred, and we don't know
|
||||
* whether we have already tidied the NSPortCoder object up or not.
|
||||
*/
|
||||
- (void) _failOutRmc: (NSPortCoder*)c
|
||||
{
|
||||
M_LOCK(_refGate);
|
||||
if ([_cachedEncoders indexOfObjectIdenticalTo: c] == NSNotFound)
|
||||
{
|
||||
[_cachedEncoders addObject: c];
|
||||
[c dispatch]; /* Tell NSPortCoder to release the connection. */
|
||||
RELEASE(c);
|
||||
}
|
||||
M_UNLOCK(_refGate);
|
||||
}
|
||||
|
||||
- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components
|
||||
{
|
||||
NSPortCoder *coder;
|
||||
|
@ -2403,7 +2491,7 @@ static BOOL multi_threaded = NO;
|
|||
}
|
||||
else
|
||||
{
|
||||
coder = [portCoderClass allocWithZone: NSDefaultMallocZone()];
|
||||
coder = [recvCoderClass allocWithZone: NSDefaultMallocZone()];
|
||||
}
|
||||
M_UNLOCK(_refGate);
|
||||
|
||||
|
@ -2457,7 +2545,7 @@ static BOOL multi_threaded = NO;
|
|||
}
|
||||
else
|
||||
{
|
||||
coder = [portCoderClass allocWithZone: NSDefaultMallocZone()];
|
||||
coder = [sendCoderClass allocWithZone: NSDefaultMallocZone()];
|
||||
}
|
||||
M_UNLOCK(_refGate);
|
||||
|
||||
|
@ -2799,7 +2887,7 @@ static BOOL multi_threaded = NO;
|
|||
|
||||
ip = [self _getReplyRmc: seq_num];
|
||||
[ip decodeValueOfObjCType: @encode(id) at: &result];
|
||||
DESTROY(ip);
|
||||
[self _doneInRmc: ip];
|
||||
if (result != nil)
|
||||
NSLog(@"failed to retain target - %@", result);
|
||||
}
|
||||
|
|
|
@ -222,6 +222,7 @@ callframe_do_call_opts (const char *encoded_types,
|
|||
/* Does the method have any arguments that are passed by reference?
|
||||
If so, we need to encode them, since the method may have changed them. */
|
||||
BOOL out_parameters = NO;
|
||||
BOOL one_way = NO;
|
||||
/* A dummy invocation to pass to the function that invokes our method */
|
||||
NSInvocation_t *inv;
|
||||
/* Signature information */
|
||||
|
@ -440,6 +441,10 @@ callframe_do_call_opts (const char *encoded_types,
|
|||
int dummy = 0;
|
||||
(*encoder) (-1, (void*)&dummy, @encode(int), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
one_way = YES;
|
||||
}
|
||||
/* No return value to encode; do nothing. */
|
||||
break;
|
||||
|
||||
|
|
Loading…
Reference in a new issue