mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-13 01:20:57 +00:00
Implemented NSZombie stuff
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@13247 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
58355c8ac0
commit
cd71e84dee
7 changed files with 232 additions and 63 deletions
|
@ -1,3 +1,11 @@
|
||||||
|
2002-03-27 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* Source/GSPrivate.h: Added function to fetch boolean value from env
|
||||||
|
* Source/NSException.m: Use new function.
|
||||||
|
* Source/NSProcesInfo.m: Implement new function.
|
||||||
|
* Source/NSObject.m: Implement NSZombie functionality.
|
||||||
|
* Headers/Foundation/NSDebug.h: Document NSZombie functionality.
|
||||||
|
|
||||||
2002-03-25 Richard Frith-Macdonald <rfm@gnu.org>
|
2002-03-25 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSTask.m: Implement code to watch for child process exit
|
* Source/NSTask.m: Implement code to watch for child process exit
|
||||||
|
|
|
@ -111,6 +111,43 @@ GS_EXPORT NSString* GSDebugMethodMsg(id obj, SEL sel, const char *file,
|
||||||
int line, NSString *fmt);
|
int line, NSString *fmt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable zombies.
|
||||||
|
* <p>When an object is deallocated, its isa pointer is normally modified
|
||||||
|
* to the hexadecimal value 0xdeadface, so that any attempt to send a
|
||||||
|
* message to the deallocated object will cause a crash, and examination
|
||||||
|
* of the object within the debugger will show the 0xdeadface value ...
|
||||||
|
* making it obvious why the program crashed.
|
||||||
|
* </p>
|
||||||
|
* <p>Turning on zombies changes this behavior so that the isa pointer
|
||||||
|
* is modified to be that of the NSZombie class. When messages are
|
||||||
|
* sent to the object, intead of crashing, NSZombie will use NSLog() to
|
||||||
|
* produce an error message. By default the memory used by the object
|
||||||
|
* will not really be freed, so error messages will continue to
|
||||||
|
* be generated whenever a message is sent to the object, and the object
|
||||||
|
* instance variables will remain available for examination by the debugger.
|
||||||
|
* </p>
|
||||||
|
* The default value of this boolean is NO, but this can be controlled
|
||||||
|
* by the NSZombieEnabled environment variable.
|
||||||
|
*/
|
||||||
|
GS_EXPORT BOOL NSZombieEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/disable object deallocation.
|
||||||
|
* <p>If zombies are enabled, objects are by default <em>not</em>
|
||||||
|
* deallocated, and memory leaks. The NSDeallocateZombies variable
|
||||||
|
* lets you say that the the memory used by zombies should be freed.
|
||||||
|
* </p>
|
||||||
|
* <p>Doing this makes the behavior of zombies similar to that when zombies
|
||||||
|
* are not enabled ... the memory occupied by the zombie may be re-used for
|
||||||
|
* other purposes, at which time the isa pointer may be overwritten and the
|
||||||
|
* zombie behavior will cease.
|
||||||
|
* </p>
|
||||||
|
* The default value of this boolean is NO, but this can be controlled
|
||||||
|
* by the NSDeallocateZombies environment variable.
|
||||||
|
*/
|
||||||
|
GS_EXPORT BOOL NSDeallocateZombies;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Debug logging which can be enabled/disabled by defining GSDIAGNOSE
|
/* Debug logging which can be enabled/disabled by defining GSDIAGNOSE
|
||||||
|
|
|
@ -80,7 +80,12 @@ NSDictionary *GSUserDefaultsDictionaryRepresentation();
|
||||||
/*
|
/*
|
||||||
* Get one of several potentially useful flags.
|
* Get one of several potentially useful flags.
|
||||||
*/
|
*/
|
||||||
BOOL GSUserDefaultsFlag(GSUserDefaultFlagType type);
|
BOOL GSUserDefaultsFlag(GSUserDefaultFlagType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a flag from an environment variable - return def if not defined.
|
||||||
|
*/
|
||||||
|
BOOL GSEnvironmentFlag(const char *name, BOOL def);
|
||||||
|
|
||||||
#endif /* __GSPrivate_h_ */
|
#endif /* __GSPrivate_h_ */
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,8 @@
|
||||||
#include <Foundation/NSThread.h>
|
#include <Foundation/NSThread.h>
|
||||||
#include <Foundation/NSDictionary.h>
|
#include <Foundation/NSDictionary.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h> // for getenv()
|
|
||||||
|
#include "GSPrivate.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_preventRecursion (NSException *exception)
|
_preventRecursion (NSException *exception)
|
||||||
|
@ -43,7 +44,6 @@ _preventRecursion (NSException *exception)
|
||||||
static void
|
static void
|
||||||
_NSFoundationUncaughtExceptionHandler (NSException *exception)
|
_NSFoundationUncaughtExceptionHandler (NSException *exception)
|
||||||
{
|
{
|
||||||
const char *c = getenv("CRASH_ON_ABORT");
|
|
||||||
BOOL a;
|
BOOL a;
|
||||||
|
|
||||||
_NSUncaughtExceptionHandler = _preventRecursion;
|
_NSUncaughtExceptionHandler = _preventRecursion;
|
||||||
|
@ -60,33 +60,7 @@ _NSFoundationUncaughtExceptionHandler (NSException *exception)
|
||||||
#else
|
#else
|
||||||
a = NO; // exit() by default.
|
a = NO; // exit() by default.
|
||||||
#endif
|
#endif
|
||||||
if (c != 0)
|
a = GSEnvironmentFlag("CRASH_ON_ABORT", a);
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Use the CRASH_ON_ABORT environment variable ... if it's defined
|
|
||||||
* then we use abort(), unless it's 'no', 'false', or '0, in which
|
|
||||||
* case we use exit()
|
|
||||||
*/
|
|
||||||
if (c[0] == '0' && c[1] == 0)
|
|
||||||
{
|
|
||||||
a = NO;
|
|
||||||
}
|
|
||||||
else if ((c[0] == 'n' || c[0] == 'N') && (c[1] == 'o' || c[1] == 'O')
|
|
||||||
&& c[2] == 0)
|
|
||||||
{
|
|
||||||
a = NO;
|
|
||||||
}
|
|
||||||
else if ((c[0] == 'f' || c[0] == 'F') && (c[1] == 'a' || c[1] == 'A')
|
|
||||||
&& (c[2] == 'l' || c[2] == 'L') && (c[3] == 's' || c[3] == 'S')
|
|
||||||
&& (c[4] == 'e' || c[4] == 'E') && c[5] == 0)
|
|
||||||
{
|
|
||||||
a = NO;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a = YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (a == YES)
|
if (a == YES)
|
||||||
{
|
{
|
||||||
abort();
|
abort();
|
||||||
|
|
|
@ -42,8 +42,10 @@
|
||||||
#include <Foundation/NSThread.h>
|
#include <Foundation/NSThread.h>
|
||||||
#include <Foundation/NSNotification.h>
|
#include <Foundation/NSNotification.h>
|
||||||
#include <Foundation/NSObjCRuntime.h>
|
#include <Foundation/NSObjCRuntime.h>
|
||||||
|
#include <Foundation/NSMapTable.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "GSPrivate.h"
|
||||||
|
|
||||||
|
|
||||||
#ifndef NeXT_RUNTIME
|
#ifndef NeXT_RUNTIME
|
||||||
|
@ -61,6 +63,68 @@ static Class NSConstantStringClass;
|
||||||
|
|
||||||
static BOOL deallocNotifications = NO;
|
static BOOL deallocNotifications = NO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* allocationLock is needed when running multi-threaded for retain/release
|
||||||
|
* to work reliably.
|
||||||
|
* We also use it for protecting the map table of zombie information.
|
||||||
|
*/
|
||||||
|
static objc_mutex_t allocationLock = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
BOOL NSZombieEnabled = NO;
|
||||||
|
BOOL NSDeallocateZombies = NO;
|
||||||
|
|
||||||
|
@class NSZombie;
|
||||||
|
static Class zombieClass;
|
||||||
|
static NSMapTable zombieMap;
|
||||||
|
|
||||||
|
static void GSMakeZombie(NSObject *o)
|
||||||
|
{
|
||||||
|
Class c = ((id)o)->class_pointer;
|
||||||
|
|
||||||
|
((id)o)->class_pointer = zombieClass;
|
||||||
|
if (NSDeallocateZombies == NO)
|
||||||
|
{
|
||||||
|
if (allocationLock == 0)
|
||||||
|
{
|
||||||
|
objc_mutex_lock(allocationLock);
|
||||||
|
}
|
||||||
|
NSMapInsert(zombieMap, (void*)o, (void*)c);
|
||||||
|
if (allocationLock == 0)
|
||||||
|
{
|
||||||
|
objc_mutex_unlock(allocationLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GSLogZombie(id o, SEL sel)
|
||||||
|
{
|
||||||
|
Class c = 0;
|
||||||
|
|
||||||
|
if (NSDeallocateZombies == NO)
|
||||||
|
{
|
||||||
|
if (allocationLock == 0)
|
||||||
|
{
|
||||||
|
objc_mutex_lock(allocationLock);
|
||||||
|
}
|
||||||
|
c = NSMapGet(zombieMap, (void*)o);
|
||||||
|
if (allocationLock == 0)
|
||||||
|
{
|
||||||
|
objc_mutex_unlock(allocationLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == 0)
|
||||||
|
{
|
||||||
|
NSLog(@"Deallocated object (0x%x) sent %@",
|
||||||
|
o, NSStringFromSelector(sel));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSLog(@"Deallocated %@ (0x%x) sent %@",
|
||||||
|
NSStringFromClass(c), o, NSStringFromSelector(sel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference count and memory management
|
* Reference count and memory management
|
||||||
|
@ -76,12 +140,6 @@ static BOOL deallocNotifications = NO;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* retain_counts_gate is needed when running multi-threaded for retain/release
|
|
||||||
* to work reliably.
|
|
||||||
*/
|
|
||||||
static objc_mutex_t retain_counts_gate = NULL;
|
|
||||||
|
|
||||||
#if GS_WITH_GC == 0 && !defined(NeXT_RUNTIME)
|
#if GS_WITH_GC == 0 && !defined(NeXT_RUNTIME)
|
||||||
#define REFCNT_LOCAL 1
|
#define REFCNT_LOCAL 1
|
||||||
#define CACHE_ZONE 1
|
#define CACHE_ZONE 1
|
||||||
|
@ -165,11 +223,11 @@ NSExtraRefCount(id anObject)
|
||||||
void
|
void
|
||||||
NSIncrementExtraRefCount(id anObject)
|
NSIncrementExtraRefCount(id anObject)
|
||||||
{
|
{
|
||||||
if (retain_counts_gate != 0)
|
if (allocationLock != 0)
|
||||||
{
|
{
|
||||||
objc_mutex_lock(retain_counts_gate);
|
objc_mutex_lock(allocationLock);
|
||||||
((obj)anObject)[-1].retained++;
|
((obj)anObject)[-1].retained++;
|
||||||
objc_mutex_unlock (retain_counts_gate);
|
objc_mutex_unlock (allocationLock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -178,11 +236,11 @@ NSIncrementExtraRefCount(id anObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NSIncrementExtraRefCount(X) ({ \
|
#define NSIncrementExtraRefCount(X) ({ \
|
||||||
if (retain_counts_gate != 0) \
|
if (allocationLock != 0) \
|
||||||
{ \
|
{ \
|
||||||
objc_mutex_lock(retain_counts_gate); \
|
objc_mutex_lock(allocationLock); \
|
||||||
((obj)(X))[-1].retained++; \
|
((obj)(X))[-1].retained++; \
|
||||||
objc_mutex_unlock(retain_counts_gate); \
|
objc_mutex_unlock(allocationLock); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
|
@ -193,17 +251,17 @@ NSIncrementExtraRefCount(id anObject)
|
||||||
BOOL
|
BOOL
|
||||||
NSDecrementExtraRefCountWasZero(id anObject)
|
NSDecrementExtraRefCountWasZero(id anObject)
|
||||||
{
|
{
|
||||||
if (retain_counts_gate != 0)
|
if (allocationLock != 0)
|
||||||
{
|
{
|
||||||
objc_mutex_lock(retain_counts_gate);
|
objc_mutex_lock(allocationLock);
|
||||||
if (((obj)anObject)[-1].retained-- == 0)
|
if (((obj)anObject)[-1].retained-- == 0)
|
||||||
{
|
{
|
||||||
objc_mutex_unlock(retain_counts_gate);
|
objc_mutex_unlock(allocationLock);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
objc_mutex_unlock(retain_counts_gate);
|
objc_mutex_unlock(allocationLock);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,9 +303,9 @@ NSIncrementExtraRefCount (id anObject)
|
||||||
{
|
{
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
|
|
||||||
if (retain_counts_gate != 0)
|
if (allocationLock != 0)
|
||||||
{
|
{
|
||||||
objc_mutex_lock(retain_counts_gate);
|
objc_mutex_lock(allocationLock);
|
||||||
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
||||||
if (node != 0)
|
if (node != 0)
|
||||||
{
|
{
|
||||||
|
@ -257,7 +315,7 @@ NSIncrementExtraRefCount (id anObject)
|
||||||
{
|
{
|
||||||
GSIMapAddPair(&retain_counts, (GSIMapKey)anObject, (GSIMapVal)1);
|
GSIMapAddPair(&retain_counts, (GSIMapKey)anObject, (GSIMapVal)1);
|
||||||
}
|
}
|
||||||
objc_mutex_unlock(retain_counts_gate);
|
objc_mutex_unlock(allocationLock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -278,13 +336,13 @@ NSDecrementExtraRefCountWasZero (id anObject)
|
||||||
{
|
{
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
|
|
||||||
if (retain_counts_gate != 0)
|
if (allocationLock != 0)
|
||||||
{
|
{
|
||||||
objc_mutex_lock(retain_counts_gate);
|
objc_mutex_lock(allocationLock);
|
||||||
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
||||||
if (node == 0)
|
if (node == 0)
|
||||||
{
|
{
|
||||||
objc_mutex_unlock(retain_counts_gate);
|
objc_mutex_unlock(allocationLock);
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
NSCAssert(node->value.uint > 0, NSInternalInconsistencyException);
|
NSCAssert(node->value.uint > 0, NSInternalInconsistencyException);
|
||||||
|
@ -292,7 +350,7 @@ NSDecrementExtraRefCountWasZero (id anObject)
|
||||||
{
|
{
|
||||||
GSIMapRemoveKey((GSIMapTable)&retain_counts, (GSIMapKey)anObject);
|
GSIMapRemoveKey((GSIMapTable)&retain_counts, (GSIMapKey)anObject);
|
||||||
}
|
}
|
||||||
objc_mutex_unlock(retain_counts_gate);
|
objc_mutex_unlock(allocationLock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -316,9 +374,9 @@ NSExtraRefCount (id anObject)
|
||||||
GSIMapNode node;
|
GSIMapNode node;
|
||||||
unsigned ret;
|
unsigned ret;
|
||||||
|
|
||||||
if (retain_counts_gate != 0)
|
if (allocationLock != 0)
|
||||||
{
|
{
|
||||||
objc_mutex_lock(retain_counts_gate);
|
objc_mutex_lock(allocationLock);
|
||||||
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
node = GSIMapNodeForKey(&retain_counts, (GSIMapKey)anObject);
|
||||||
if (node == 0)
|
if (node == 0)
|
||||||
{
|
{
|
||||||
|
@ -328,7 +386,7 @@ NSExtraRefCount (id anObject)
|
||||||
{
|
{
|
||||||
ret = node->value.uint;
|
ret = node->value.uint;
|
||||||
}
|
}
|
||||||
objc_mutex_unlock(retain_counts_gate);
|
objc_mutex_unlock(allocationLock);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -501,8 +559,19 @@ NSDeallocateObject(NSObject *anObject)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject);
|
GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject);
|
||||||
#endif
|
#endif
|
||||||
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
if (NSZombieEnabled == YES)
|
||||||
NSZoneFree(z, o);
|
{
|
||||||
|
GSMakeZombie(anObject);
|
||||||
|
if (NSDeallocateZombies == YES)
|
||||||
|
{
|
||||||
|
NSZoneFree(z, o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
||||||
|
NSZoneFree(z, o);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -545,8 +614,19 @@ NSDeallocateObject(NSObject *anObject)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject);
|
GSDebugAllocationRemove(((id)anObject)->class_pointer, (id)anObject);
|
||||||
#endif
|
#endif
|
||||||
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
if (NSZombieEnabled == YES)
|
||||||
NSZoneFree(z, anObject);
|
{
|
||||||
|
GSMakeZombie(anObject);
|
||||||
|
if (NSDeallocateZombies == YES)
|
||||||
|
{
|
||||||
|
NSZoneFree(z, anObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((id)anObject)->class_pointer = (void*) 0xdeadface;
|
||||||
|
NSZoneFree(z, anObject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -562,7 +642,7 @@ NSShouldRetainWithZone (NSObject *anObject, NSZone *requestedZone)
|
||||||
return YES;
|
return YES;
|
||||||
#else
|
#else
|
||||||
return (!requestedZone || requestedZone == NSDefaultMallocZone()
|
return (!requestedZone || requestedZone == NSDefaultMallocZone()
|
||||||
|| GSObjCZone(anObject) == requestedZone);
|
|| GSObjCZone(anObject) == requestedZone);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,9 +667,9 @@ static BOOL double_release_check_enabled = NO;
|
||||||
|
|
||||||
+ (void) _becomeMultiThreaded: (NSNotification)aNotification
|
+ (void) _becomeMultiThreaded: (NSNotification)aNotification
|
||||||
{
|
{
|
||||||
if (retain_counts_gate == 0)
|
if (allocationLock == 0)
|
||||||
{
|
{
|
||||||
retain_counts_gate = objc_mutex_allocate();
|
allocationLock = objc_mutex_allocate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,6 +710,14 @@ static BOOL double_release_check_enabled = NO;
|
||||||
|
|
||||||
// Create the global lock
|
// Create the global lock
|
||||||
gnustep_global_lock = [[NSRecursiveLock alloc] init];
|
gnustep_global_lock = [[NSRecursiveLock alloc] init];
|
||||||
|
|
||||||
|
// Zombie management stuff.
|
||||||
|
zombieClass = [NSZombie class];
|
||||||
|
zombieMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
||||||
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
||||||
|
NSZombieEnabled = GSEnvironmentFlag("NSZombieEnabled", NO);
|
||||||
|
NSDeallocateZombies = GSEnvironmentFlag("NSDeallocateZombies", NO);
|
||||||
|
|
||||||
autorelease_class = [NSAutoreleasePool class];
|
autorelease_class = [NSAutoreleasePool class];
|
||||||
autorelease_sel = @selector(addObject:);
|
autorelease_sel = @selector(addObject:);
|
||||||
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
|
autorelease_imp = [autorelease_class methodForSelector: autorelease_sel];
|
||||||
|
@ -1542,3 +1630,28 @@ _fastMallocBuffer(unsigned size)
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@interface NSZombie
|
||||||
|
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame;
|
||||||
|
- (void) forwardInvocation: (NSInvocation*)anInvocation;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSZombie
|
||||||
|
- (retval_t) forward:(SEL)aSel :(arglist_t)argFrame
|
||||||
|
{
|
||||||
|
GSLogZombie(self, aSel);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
||||||
|
{
|
||||||
|
unsigned size = [[anInvocation methodSignature] methodReturnLength];
|
||||||
|
unsigned char v[size];
|
||||||
|
|
||||||
|
memset(v, '\0', size);
|
||||||
|
GSLogZombie(self, [anInvocation selector]);
|
||||||
|
[anInvocation setReturnValue: (void*)v];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,8 @@
|
||||||
#include <Foundation/NSAutoreleasePool.h>
|
#include <Foundation/NSAutoreleasePool.h>
|
||||||
#include <Foundation/NSHost.h>
|
#include <Foundation/NSHost.h>
|
||||||
|
|
||||||
|
#include "GSPrivate.h"
|
||||||
|
|
||||||
/* This error message should be called only if the private main function
|
/* This error message should be called only if the private main function
|
||||||
* was not executed successfully. This may happen ONLY if another library
|
* was not executed successfully. This may happen ONLY if another library
|
||||||
* or kit defines its own main function (as gnustep-base does).
|
* or kit defines its own main function (as gnustep-base does).
|
||||||
|
@ -679,3 +681,32 @@ BOOL GSDebugSet(NSString *level)
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
GSEnvironmentFlag(const char *name, BOOL def)
|
||||||
|
{
|
||||||
|
const char *c = getenv(name);
|
||||||
|
BOOL a = def;
|
||||||
|
|
||||||
|
if (c != 0)
|
||||||
|
{
|
||||||
|
a = NO;
|
||||||
|
if ((c[0] == 'y' || c[0] == 'Y') && (c[1] == 'e' || c[1] == 'E')
|
||||||
|
&& (c[2] == 's' || c[2] == 'S') && c[3] == 0)
|
||||||
|
{
|
||||||
|
a = YES;
|
||||||
|
}
|
||||||
|
else if ((c[0] == 't' || c[0] == 'T') && (c[1] == 'r' || c[1] == 'R')
|
||||||
|
&& (c[2] == 'u' || c[2] == 'U') && (c[3] == 'e' || c[3] == 'E')
|
||||||
|
&& c[4] == 0)
|
||||||
|
{
|
||||||
|
a = YES;
|
||||||
|
}
|
||||||
|
else if (isdigit(c[0]) && c[0] != '0')
|
||||||
|
{
|
||||||
|
a = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ int main ()
|
||||||
id o = [NSObject new];
|
id o = [NSObject new];
|
||||||
printf ("Hello from object at 0x%x\n", (unsigned)[o self]);
|
printf ("Hello from object at 0x%x\n", (unsigned)[o self]);
|
||||||
|
|
||||||
|
[o release];
|
||||||
o = [NSString stringWithFormat: @"/proc/%d/status", getpid()];
|
o = [NSString stringWithFormat: @"/proc/%d/status", getpid()];
|
||||||
NSLog(@"'%@'", o);
|
NSLog(@"'%@'", o);
|
||||||
o = [NSString stringWithContentsOfFile: o];
|
o = [NSString stringWithContentsOfFile: o];
|
||||||
|
|
Loading…
Reference in a new issue