mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 08:41:03 +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
00963be77a
commit
fda6ac643b
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>
|
2013-10-29 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/GSAttributedString.m:
|
* Source/GSAttributedString.m:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue