Add +trackOwnership method to trace tetain/release for objects of a class

This commit is contained in:
rfm 2024-11-20 14:27:44 +00:00
parent da73bc5e9b
commit 2278c79f62
2 changed files with 109 additions and 0 deletions

View file

@ -295,6 +295,8 @@ extern "C" {
*/
+ (BOOL) shouldCleanUp;
+ (void) trackOwnership;
@end
/* Macro to take an autoreleased object and either make it immutable or

View file

@ -419,6 +419,113 @@ handleExit()
return shouldCleanUp;
}
struct trackLink {
struct trackLink *next;
Class cls; // Class whose instaances are tracked.
IMP release; // Original -release implementation
IMP retain; // Original -retain implementation
};
static struct trackLink *tracked = 0;
static gs_mutex_t trackLock = GS_MUTEX_INIT_STATIC;
- (void) _replacementRelease
{
struct trackLink *l;
Class c = object_getClass(self);
IMP release = 0;
unsigned rc;
GS_MUTEX_LOCK(trackLock);
l = tracked;
while (l)
{
if (l->cls == c)
{
release = l->release;
break;
}
l = l->next;
}
GS_MUTEX_UNLOCK(trackLock);
rc = (unsigned)[self retainCount];
NSLog(@"-[%p release] %u->%u at %@",
self, rc, rc-1, [NSThread callStackSymbols]);
(*release)(self, _cmd);
}
- (id) _replacementRetain
{
struct trackLink *l;
Class c = object_getClass(self);
IMP retain = 0;
id result;
unsigned rc;
GS_MUTEX_LOCK(trackLock);
l = tracked;
while (l)
{
if (l->cls == c)
{
retain = l->retain;
break;
}
l = l->next;
}
GS_MUTEX_UNLOCK(trackLock);
rc = (unsigned)[self retainCount];
result = (*retain)(self, _cmd);
NSLog(@"-[%p retain] %u->%u at %@",
self, rc, (unsigned)[self retainCount], [NSThread callStackSymbols]);
return result;
}
+ (void) trackOwnership
{
Method replacementRelease;
Method replacementRetain;
Class c = object_getClass(self);
struct trackLink *l;
if (class_isMetaClass(c))
{
c = self;
}
GS_MUTEX_LOCK(trackLock);
l = tracked;
while (l)
{
if (l->cls == c)
{
GS_MUTEX_UNLOCK(trackLock);
return;
}
l = l->next;
}
replacementRelease = class_getInstanceMethod([NSObject class],
@selector(_replacementRelease));
replacementRetain = class_getInstanceMethod([NSObject class],
@selector(_replacementRetain));
l = (struct trackLink*)malloc(sizeof(struct trackLink));
l->cls = c;
l->release = class_getMethodImplementation(c, @selector(release));
class_replaceMethod(c, @selector(release),
method_getImplementation(replacementRelease),
method_getTypeEncoding(replacementRelease));
l->retain = class_getMethodImplementation(c, @selector(retain));
class_replaceMethod(c, @selector(retain),
method_getImplementation(replacementRetain),
method_getTypeEncoding(replacementRetain));
l->next = tracked;
tracked = l;
GS_MUTEX_UNLOCK(trackLock);
}
@end
#else