mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
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:
parent
7162dc6fcd
commit
5b7cf5f19c
3 changed files with 48 additions and 14 deletions
|
@ -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>
|
||||
|
||||
* 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<GSCachedDictionary> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue