Index: src/OFMapTable.m ================================================================== --- src/OFMapTable.m +++ src/OFMapTable.m @@ -16,10 +16,12 @@ #include "config.h" #include #include + +#include #include #import "OFMapTable.h" #import "OFEnumerator.h" @@ -290,11 +292,11 @@ return NULL; } - (void)OF_resizeForCount: (uint32_t)newCount { - uint32_t i, fullness, newCapacity; + uint32_t i, fullness, newCapacity, newSeed = 0, seedUpdate = 0; struct of_map_table_bucket **newBuckets; if (newCount > UINT32_MAX || newCount > UINT32_MAX / sizeof(*buckets) || newCount > UINT32_MAX / 8) @throw [OFOutOfRangeException exceptionWithClass: [self class]]; @@ -314,14 +316,27 @@ newBuckets = [self allocMemoryWithSize: sizeof(*newBuckets) count: newCapacity]; for (i = 0; i < newCapacity; i++) newBuckets[i] = NULL; + + if (of_hash_seed != 0) { +#if defined(OF_HAVE_ARC4RANDOM) + newSeed = arc4random(); +#elif defined(OF_HAVE_RANDOM) + newSeed = random(); +#else + newSeed = rand(); +#endif + seedUpdate = seed ^ newSeed; + } for (i = 0; i < capacity; i++) { if (buckets[i] != NULL && buckets[i] != &deleted) { uint32_t j, last; + + buckets[i]->hash ^= seedUpdate; last = newCapacity; j = buckets[i]->hash & (newCapacity - 1); for (; j < last && newBuckets[j] != NULL; j++); @@ -332,51 +347,49 @@ for (j = 0; j < last && newBuckets[j] != NULL; j++); } - if (j >= last) { - [self freeMemory: newBuckets]; - @throw [OFOutOfRangeException - exceptionWithClass: [self class]]; - } + assert(j < last); newBuckets[j] = buckets[i]; } } [self freeMemory: buckets]; buckets = newBuckets; capacity = newCapacity; + seed = newSeed; } - (void)OF_setValue: (void*)value forKey: (void*)key hash: (uint32_t)hash { - uint32_t i, last; + uint32_t i, last, seededHash; void *old; if (key == NULL || value == NULL) @throw [OFInvalidArgumentException exceptionWithClass: [self class] selector: _cmd]; last = capacity; - hash ^= seed; + seededHash = hash ^ seed; - for (i = hash & (capacity - 1); i < last && buckets[i] != NULL; i++) { + for (i = seededHash & (capacity - 1); i < last && buckets[i] != NULL; + i++) { if (buckets[i] == &deleted) continue; if (keyFunctions.equal(buckets[i]->key, key)) break; } /* In case the last bucket is already used */ if (i >= last) { - last = hash & (capacity - 1); + last = seededHash & (capacity - 1); for (i = 0; i < last && buckets[i] != NULL; i++) { if (buckets[i] == &deleted) continue; @@ -389,20 +402,21 @@ if (i >= last || buckets[i] == NULL || buckets[i] == &deleted || !keyFunctions.equal(buckets[i]->key, key)) { struct of_map_table_bucket *bucket; [self OF_resizeForCount: count + 1]; + seededHash = hash ^ seed; mutations++; last = capacity; - for (i = hash & (capacity - 1); i < last && + for (i = seededHash & (capacity - 1); i < last && buckets[i] != NULL && buckets[i] != &deleted; i++); /* In case the last bucket is already used */ if (i >= last) { - last = hash & (capacity - 1); + last = seededHash & (capacity - 1); for (i = 0; i < last && buckets[i] != NULL && buckets[i] != &deleted; i++); } @@ -425,11 +439,11 @@ keyFunctions.release(key); [self freeMemory: bucket]; @throw e; } - bucket->hash = hash; + bucket->hash = seededHash; buckets[i] = bucket; count++; return;