Skip to content

Instantly share code, notes, and snippets.

@claybridges
Created August 1, 2013 14:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save claybridges/6132147 to your computer and use it in GitHub Desktop.
Save claybridges/6132147 to your computer and use it in GitHub Desktop.
Test for bug in cache for ext_globalMethodSignatureForSelector, in libextobj.
typedef struct {
Class class;
SEL sel;
} SelStruct; // not sure about the name SelStruct, but works for now
NSString *NSStringFromSelStruct(SelStruct s) {
return [NSString stringWithFormat:@"-[%@ %@]", s.class, NSStringFromSelector(s.sel)];
}
- (void)testCache {
// test simplistic cache collisions for ext_blah
static const size_t selectorCacheLength = 1 << 8;
static const uintptr_t selectorCacheMask = (selectorCacheLength - 1);
static SelStruct selectorHash[selectorCacheLength];
unsigned classCount = 0;
Class *classes = ext_copyClassList(&classCount);
if (!classes)
return;
uint collisions = 0;
uint methodNumber = 0;
uint firstCollisionAtMethodNumber = 0;
for (uint i = 0; i < classCount; ++i) {
unsigned methodCount = 0;
// just getting instance methods, that's enough
Method *methods = class_copyMethodList(classes[i], &methodCount);
for (uint j = 0; j < methodCount; ++j) {
methodNumber++;
Method method = methods[j];
SelStruct thisSelStruct = (SelStruct) {.class = classes[i], .sel = method_getName(method)};
uintptr_t hash = (uintptr_t)(void *)thisSelStruct.sel & selectorCacheMask;
SelStruct hashedSelStruct = selectorHash[hash];
if (hashedSelStruct.sel && hashedSelStruct.sel != thisSelStruct.sel) {
collisions++;
if (!firstCollisionAtMethodNumber) {
NSLog(@"first collision with %@ and %@", NSStringFromSelStruct(hashedSelStruct),
NSStringFromSelStruct(thisSelStruct));
firstCollisionAtMethodNumber = methodNumber;
}
// uncomment this for the deluge
// NSLog(@"collision with %@ and %@", NSStringFromSelector(hashedSel), NSStringFromSelector(sel));
} else {
selectorHash[hash] = thisSelStruct;
}
}
free(methods);
}
NSLog(@"tested %d classes, %d methods, %d collisions, first collision @ method %d",
classCount, methodNumber, collisions, firstCollisionAtMethodNumber);
// use your flavor of assertation here
//XCTAssert(!collisions, @"hash collision for simple selector cache");
free(classes);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment