fix for attribute dictionaries whose contents mutate while in the cache

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@37344 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2013-11-01 06:48:20 +00:00
parent af3d05ffc7
commit a789f9e6d0
2 changed files with 33 additions and 3 deletions

View file

@ -95,11 +95,31 @@
static BOOL adding;
/* When caching attributes we make a shallow copy of the dictionary cached,
* so that it is immutable and safe to cache.
* However, we have a potential problem if the objects within the attributes
* dictionary are themselves mutable, and something mutates them while they
* are in the cache. In this case we could items added while different and
* then mutated to have the same contents, so we would not know which of
* the equal dictionaries to remove.
* The solution is to require dictionaries to be identical for removal.
*/
static inline BOOL
cacheEqual(id A, id B)
{
if (YES == adding)
return [A isEqualToDictionary: B];
else
return A == B;
}
#define GSI_MAP_RETAIN_KEY(M, X)
#define GSI_MAP_RELEASE_KEY(M, X)
#define GSI_MAP_RETAIN_VAL(M, X)
#define GSI_MAP_RELEASE_VAL(M, X)
#define GSI_MAP_EQUAL(M, X,Y) [(X).obj isEqualToDictionary: (Y).obj]
#define GSI_MAP_EQUAL(M, X,Y) cacheEqual((X).obj, (Y).obj)
#define GSI_MAP_KTYPES GSUNION_OBJ
#define GSI_MAP_VTYPES GSUNION_NSINT
#define GSI_MAP_NOCLEAN 1
@ -140,6 +160,7 @@ cacheAttributes(NSDictionary *attrs)
GSIMapNode node;
ALOCK();
adding = YES;
node = GSIMapNodeForKey(&attrMap, (GSIMapKey)((id)attrs));
if (node == 0)
{
@ -173,6 +194,7 @@ unCacheAttributes(NSDictionary *attrs)
id<GSCachedDictionary> removed = nil;
ALOCK();
adding = NO;
bucket = GSIMapBucketForKey(&attrMap, (GSIMapKey)((id)attrs));
if (bucket != 0)
{
@ -854,6 +876,7 @@ SANITY();
while (next < arraySize)
{
GSAttrInfo *n = OBJECTAT(next);
if (n->loc <= NSMaxRange(range))
{
REMOVEAT(arrayIndex);
@ -892,7 +915,7 @@ SANITY();
&& effectiveRange.length == range.length)
{
arrayIndex--;
if (arrayIndex!=0 || arraySize > 1)
if (arrayIndex != 0 || arraySize > 1)
{
REMOVEAT(arrayIndex);
arraySize--;