From fda6ac643b057921268330c2d57d50733ecea77f Mon Sep 17 00:00:00 2001 From: Richard Frith-MacDonald Date: Wed, 30 Oct 2013 04:28:17 +0000 Subject: [PATCH] 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 --- ChangeLog | 7 +++++++ Source/GSAttributedString.m | 34 ++++++++++++++++++++-------------- Source/GSDictionary.m | 21 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index dfbfb0039..2232d8bb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-10-30 Richard Frith-Macdonald + + * 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 * Source/GSAttributedString.m: diff --git a/Source/GSAttributedString.m b/Source/GSAttributedString.m index 172d8b5f8..156affa5d 100644 --- a/Source/GSAttributedString.m +++ b/Source/GSAttributedString.m @@ -59,8 +59,6 @@ #define SANITY_CHECKS 0 -static NSDictionary *blank; - @interface GSAttributedString : NSAttributedString { @@ -125,6 +123,11 @@ static IMP unlockImp; #define ALOCK() if (attrLock != nil) (*lockImp)(attrLock, lockSel) #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 * the copy added to the cache, if it was, count it and return retained * object that was there. @@ -143,8 +146,8 @@ cacheAttributes(NSDictionary *attrs) /* Shallow copy of dictionary, without copying objects .... * result in an immutable dictionary that can safely be cached. */ - attrs = [[NSDictionary alloc] initWithDictionary: attrs - copyItems: NO]; + attrs = [(NSDictionary*)[GSCachedDictionary alloc] + initWithDictionary: attrs copyItems: NO]; GSIMapAddPair(&attrMap, (GSIMapKey)((id)attrs), (GSIMapVal)(NSUInteger)1); } @@ -167,7 +170,7 @@ unCacheAttributes(NSDictionary *attrs) if (nil != attrs) { GSIMapBucket bucket; - NSDictionary *removed = nil; + id removed = nil; ALOCK(); bucket = GSIMapBucketForKey(&attrMap, (GSIMapKey)((id)attrs)); @@ -188,7 +191,10 @@ unCacheAttributes(NSDictionary *attrs) } } AUNLOCK(); - RELEASE(removed); + if (nil != removed) + { + [removed _uncache]; + } } } @@ -266,6 +272,8 @@ unCacheAttributes(NSDictionary *attrs) @implementation GSAttributedString +static GSAttrInfo *blank; + static Class infCls = 0; static SEL infSel; @@ -307,7 +315,7 @@ _setAttributesFrom( if (aRange.length == 0) { - attr = blank; + attr = blank->attrs; range = aRange; /* Set to satisfy the loop condition below. */ } else @@ -451,7 +459,7 @@ _attributesAtIndexEffectiveRange( [a methodForSelector: remSel]; RELEASE(a); d = [NSDictionary new]; - blank = cacheAttributes(d); + blank = NEWINFO(NSDefaultMallocZone(), d, 0); [[NSObject leakAt: &blank] release]; RELEASE(d); } @@ -495,7 +503,7 @@ _attributesAtIndexEffectiveRange( if (attributes == nil) { - attributes = blank; + attributes = blank->attrs; } info = NEWINFO(z, attributes, 0); ADDOBJECT(info); @@ -604,7 +612,7 @@ _attributesAtIndexEffectiveRange( if (attributes == nil) { - attributes = blank; + attributes = blank->attrs; } info = NEWINFO(z, attributes, 0); ADDOBJECT(info); @@ -672,7 +680,7 @@ SANITY(); } if (attributes == nil) { - attributes = blank; + attributes = blank->attrs; } SANITY(); tmpLength = [_textChars length]; @@ -883,11 +891,9 @@ SANITY(); } else { - NSDictionary *d = blank; - info = OBJECTAT(0); unCacheAttributes(info->attrs); - info->attrs = cacheAttributes(d); + info->attrs = cacheAttributes(blank->attrs); info->loc = NSMaxRange(range); } } diff --git a/Source/GSDictionary.m b/Source/GSDictionary.m index 87ec82ab0..e1d326063 100644 --- a/Source/GSDictionary.m +++ b/Source/GSDictionary.m @@ -543,3 +543,24 @@ static SEL objSel; } @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