Implement dast enumeration mutation checks and add testcases for NSPointerArray

This commit is contained in:
rfm 2025-01-19 08:42:12 +00:00
parent 39b1b7fd01
commit c225efa3ba
2 changed files with 49 additions and 6 deletions

View file

@ -44,6 +44,7 @@ static Class concreteClass = Nil;
void **_contents; void **_contents;
unsigned _capacity; unsigned _capacity;
unsigned _grow_factor; unsigned _grow_factor;
unsigned long _version;
} }
@end @end
@ -203,7 +204,7 @@ static Class concreteClass = Nil;
{ {
NSInteger count; NSInteger count;
state->mutationsPtr = (unsigned long *)&state->mutationsPtr; state->mutationsPtr = state->mutationsPtr;
count = MIN(len, [self count] - state->state); count = MIN(len, [self count] - state->state);
if (count > 0) if (count > 0)
{ {
@ -312,6 +313,8 @@ static Class concreteClass = Nil;
NSUInteger insert = 0; NSUInteger insert = 0;
NSUInteger i; NSUInteger i;
_version++;
/* We can't use memmove here for __weak pointers, because that would omit the /* We can't use memmove here for __weak pointers, because that would omit the
* required read barriers. We could use objc_memmoveCollectable() for strong * required read barriers. We could use objc_memmoveCollectable() for strong
* pointers, but we may as well use the same code path for everything * pointers, but we may as well use the same code path for everything
@ -329,6 +332,7 @@ static Class concreteClass = Nil;
} }
} }
_count = insert; _count = insert;
_version++;
} }
- (id) copyWithZone: (NSZone*)zone - (id) copyWithZone: (NSZone*)zone
@ -355,6 +359,16 @@ static Class concreteClass = Nil;
return _count; return _count;
} }
- (NSUInteger) countByEnumeratingWithState: (NSFastEnumerationState*)state
objects: (__unsafe_unretained id[])stackbuf
count: (NSUInteger)len
{
state->mutationsPtr = &_version;
return [super countByEnumeratingWithState: state
objects: stackbuf
count: len];
}
- (void) dealloc - (void) dealloc
{ {
int i; int i;
@ -529,6 +543,7 @@ static Class concreteClass = Nil;
- (void) removePointerAtIndex: (NSUInteger)index - (void) removePointerAtIndex: (NSUInteger)index
{ {
_version++;
if (index >= _count) if (index >= _count)
{ {
[self _raiseRangeExceptionWithIndex: index from: _cmd]; [self _raiseRangeExceptionWithIndex: index from: _cmd];
@ -539,15 +554,18 @@ static Class concreteClass = Nil;
pointerFunctionsMove(&_pf, &_contents[index-1], &_contents[index]); pointerFunctionsMove(&_pf, &_contents[index-1], &_contents[index]);
} }
_contents[--_count] = NULL; _contents[--_count] = NULL;
_version++;
} }
- (void) replacePointerAtIndex: (NSUInteger)index withPointer: (void*)item - (void) replacePointerAtIndex: (NSUInteger)index withPointer: (void*)item
{ {
_version++;
if (index >= _count) if (index >= _count)
{ {
[self _raiseRangeExceptionWithIndex: index from: _cmd]; [self _raiseRangeExceptionWithIndex: index from: _cmd];
} }
pointerFunctionsReplace(&_pf, &_contents[index], item); pointerFunctionsReplace(&_pf, &_contents[index], item);
_version++;
} }
@ -555,6 +573,7 @@ static Class concreteClass = Nil;
- (void) setCount: (NSUInteger)count - (void) setCount: (NSUInteger)count
{ {
_version++;
if (count > _count) if (count > _count)
{ {
#if ZEROING #if ZEROING
@ -629,6 +648,7 @@ static Class concreteClass = Nil;
pointerFunctionsRelinquish(&_pf, &_contents[_count]); pointerFunctionsRelinquish(&_pf, &_contents[_count]);
} }
} }
_version++;
} }
@end @end

View file

@ -1,8 +1,4 @@
#import <Foundation/NSArray.h> #import <Foundation/Foundation.h>
#import <Foundation/NSAutoreleasePool.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSSet.h>
#import <Foundation/NSOrderedSet.h>
#import "ObjectTesting.h" #import "ObjectTesting.h"
#import "../../../Source/GSFastEnumeration.h" #import "../../../Source/GSFastEnumeration.h"
@ -10,6 +6,25 @@ static SEL add;
static SEL set; static SEL set;
static SEL key; static SEL key;
@implementation NSPointerArray (TestHelpers)
- (void) addObject: (id)anObject
{
[self addPointer: anObject];
}
- (void) removeObject: (id)anObject
{
int i = [self count];
while (i-- > 0)
{
if ([self pointerAtIndex: i] == (void*)anObject)
{
[self removePointerAtIndex: i];
}
}
}
@end
void fast_enumeration_mutation_add(id mutableCollection) void fast_enumeration_mutation_add(id mutableCollection)
{ {
NSUInteger i = 0; NSUInteger i = 0;
@ -139,6 +154,14 @@ int main()
test_fast_enumeration(table, objects); test_fast_enumeration(table, objects);
END_SET("NSHashTable") END_SET("NSHashTable")
START_SET("NSPointerArray")
id array = [NSPointerArray weakObjectsPointerArray];
FOR_IN(id, o, objects)
[array addPointer: o];
END_FOR_IN(objects)
test_fast_enumeration(array, objects);
END_SET("NSPointerArray")
[arp release]; arp = nil; [arp release]; arp = nil;
return 0; return 0;
} }