Add code to make allocation error tracking easier for Nikolaus Schaller

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@37327 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2013-10-30 04:28:17 +00:00
parent 00963be77a
commit fda6ac643b
3 changed files with 48 additions and 14 deletions

View file

@ -1,3 +1,10 @@
2013-10-30 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSDictionary.m: Add priovate class GSCachedDictionary which
will raise an exception if deallocated without being uncached.
* Source/GSAttributedString.m: Use GSCachedDictionary for attributes
to aid in detection of things improperly releasing them.
2013-10-29 Richard Frith-Macdonald <rfm@gnu.org> 2013-10-29 Richard Frith-Macdonald <rfm@gnu.org>
* Source/GSAttributedString.m: * Source/GSAttributedString.m:

View file

@ -59,8 +59,6 @@
#define SANITY_CHECKS 0 #define SANITY_CHECKS 0
static NSDictionary *blank;
@interface GSAttributedString : NSAttributedString @interface GSAttributedString : NSAttributedString
{ {
@ -125,6 +123,11 @@ static IMP unlockImp;
#define ALOCK() if (attrLock != nil) (*lockImp)(attrLock, lockSel) #define ALOCK() if (attrLock != nil) (*lockImp)(attrLock, lockSel)
#define AUNLOCK() if (attrLock != nil) (*unlockImp)(attrLock, unlockSel) #define AUNLOCK() if (attrLock != nil) (*unlockImp)(attrLock, unlockSel)
@class GSCachedDictionary;
@protocol GSCachedDictionary
- (void) _uncache;
@end
/* Add a dictionary to the cache - if it was not already there, return /* Add a dictionary to the cache - if it was not already there, return
* the copy added to the cache, if it was, count it and return retained * the copy added to the cache, if it was, count it and return retained
* object that was there. * object that was there.
@ -143,8 +146,8 @@ cacheAttributes(NSDictionary *attrs)
/* Shallow copy of dictionary, without copying objects .... /* Shallow copy of dictionary, without copying objects ....
* result in an immutable dictionary that can safely be cached. * result in an immutable dictionary that can safely be cached.
*/ */
attrs = [[NSDictionary alloc] initWithDictionary: attrs attrs = [(NSDictionary*)[GSCachedDictionary alloc]
copyItems: NO]; initWithDictionary: attrs copyItems: NO];
GSIMapAddPair(&attrMap, GSIMapAddPair(&attrMap,
(GSIMapKey)((id)attrs), (GSIMapVal)(NSUInteger)1); (GSIMapKey)((id)attrs), (GSIMapVal)(NSUInteger)1);
} }
@ -167,7 +170,7 @@ unCacheAttributes(NSDictionary *attrs)
if (nil != attrs) if (nil != attrs)
{ {
GSIMapBucket bucket; GSIMapBucket bucket;
NSDictionary *removed = nil; id<GSCachedDictionary> removed = nil;
ALOCK(); ALOCK();
bucket = GSIMapBucketForKey(&attrMap, (GSIMapKey)((id)attrs)); bucket = GSIMapBucketForKey(&attrMap, (GSIMapKey)((id)attrs));
@ -188,7 +191,10 @@ unCacheAttributes(NSDictionary *attrs)
} }
} }
AUNLOCK(); AUNLOCK();
RELEASE(removed); if (nil != removed)
{
[removed _uncache];
}
} }
} }
@ -266,6 +272,8 @@ unCacheAttributes(NSDictionary *attrs)
@implementation GSAttributedString @implementation GSAttributedString
static GSAttrInfo *blank;
static Class infCls = 0; static Class infCls = 0;
static SEL infSel; static SEL infSel;
@ -307,7 +315,7 @@ _setAttributesFrom(
if (aRange.length == 0) if (aRange.length == 0)
{ {
attr = blank; attr = blank->attrs;
range = aRange; /* Set to satisfy the loop condition below. */ range = aRange; /* Set to satisfy the loop condition below. */
} }
else else
@ -451,7 +459,7 @@ _attributesAtIndexEffectiveRange(
[a methodForSelector: remSel]; [a methodForSelector: remSel];
RELEASE(a); RELEASE(a);
d = [NSDictionary new]; d = [NSDictionary new];
blank = cacheAttributes(d); blank = NEWINFO(NSDefaultMallocZone(), d, 0);
[[NSObject leakAt: &blank] release]; [[NSObject leakAt: &blank] release];
RELEASE(d); RELEASE(d);
} }
@ -495,7 +503,7 @@ _attributesAtIndexEffectiveRange(
if (attributes == nil) if (attributes == nil)
{ {
attributes = blank; attributes = blank->attrs;
} }
info = NEWINFO(z, attributes, 0); info = NEWINFO(z, attributes, 0);
ADDOBJECT(info); ADDOBJECT(info);
@ -604,7 +612,7 @@ _attributesAtIndexEffectiveRange(
if (attributes == nil) if (attributes == nil)
{ {
attributes = blank; attributes = blank->attrs;
} }
info = NEWINFO(z, attributes, 0); info = NEWINFO(z, attributes, 0);
ADDOBJECT(info); ADDOBJECT(info);
@ -672,7 +680,7 @@ SANITY();
} }
if (attributes == nil) if (attributes == nil)
{ {
attributes = blank; attributes = blank->attrs;
} }
SANITY(); SANITY();
tmpLength = [_textChars length]; tmpLength = [_textChars length];
@ -883,11 +891,9 @@ SANITY();
} }
else else
{ {
NSDictionary *d = blank;
info = OBJECTAT(0); info = OBJECTAT(0);
unCacheAttributes(info->attrs); unCacheAttributes(info->attrs);
info->attrs = cacheAttributes(d); info->attrs = cacheAttributes(blank->attrs);
info->loc = NSMaxRange(range); info->loc = NSMaxRange(range);
} }
} }

View file

@ -543,3 +543,24 @@ static SEL objSel;
} }
@end @end
@interface GSCachedDictionary : GSDictionary
{
BOOL _uncached;
}
@end
@implementation GSCachedDictionary
- (void) dealloc
{
if (NO == _uncached)
{
[NSException raise: NSInternalInconsistencyException
format: @"Deallocating attributes which are still cached"];
}
[super dealloc];
}
- (void) _uncache
{
_uncached = YES;
RELEASE(self);
}
@end