mirror of
https://github.com/php/php-src.git
synced 2026-04-19 14:01:01 +02:00
if ZEND_DEBUG mode is on we'll now see warnings when a HashTable is accessed
while it's inconsistent. Zeev, Andi - you welcome to revert this patch if you don't like it - i find it useful! accesssing inconsistent hashtables is one of the hardest things to track!
This commit is contained in:
109
Zend/zend_hash.c
109
Zend/zend_hash.c
@@ -55,6 +55,26 @@
|
||||
} while(0); \
|
||||
}
|
||||
|
||||
#if ZEND_DEBUG
|
||||
static void _zend_is_inconsistent(HashTable *ht,char *file, int line)
|
||||
{
|
||||
switch (ht->inconsistent) {
|
||||
case 1:
|
||||
zend_error(E_CORE_ERROR, "ht=%08x is destroying in %s:%d",ht,file,line);
|
||||
break;
|
||||
case 2:
|
||||
zend_error(E_CORE_ERROR, "ht=%08x is already destroyed in %s:%d",ht,file,line);
|
||||
break;
|
||||
case 3:
|
||||
zend_error(E_CORE_ERROR, "ht=%08x is cleaning %s:%d",ht,file,line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#define IS_CONSISTENT(a) _zend_is_inconsistent(a,__FILE__,__LINE__);
|
||||
#else
|
||||
#define IS_CONSISTENT(a)
|
||||
#endif
|
||||
|
||||
/* Generated on an Octa-ALPHA 300MHz CPU & 2.5GB RAM monster */
|
||||
static uint PrimeNumbers[] =
|
||||
{5, 11, 19, 53, 107, 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987, 262237, 524521, 1048793, 2097397, 4194103, 8388857, 16777447, 33554201, 67108961, 134217487, 268435697, 536870683, 1073741621, 2147483399};
|
||||
@@ -83,6 +103,10 @@ ZEND_API int zend_hash_init(HashTable *ht, uint nSize, ulong(*pHashFunction) (ch
|
||||
{
|
||||
uint i;
|
||||
|
||||
#if ZEND_DEBUG
|
||||
ht->inconsistent = 0;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < nNumPrimeNumbers; i++) {
|
||||
if (nSize <= PrimeNumbers[i]) {
|
||||
nSize = PrimeNumbers[i];
|
||||
@@ -123,6 +147,8 @@ ZEND_API int zend_hash_add_or_update(HashTable *ht, char *arKey, uint nKeyLength
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (nKeyLength <= 0) {
|
||||
#if ZEND_DEBUG
|
||||
ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
|
||||
@@ -229,6 +255,8 @@ ZEND_API int zend_hash_quick_add_or_update(HashTable *ht, char *arKey, uint nKey
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (nKeyLength <= 0) {
|
||||
#if ZEND_DEBUG
|
||||
ZEND_PUTS("zend_hash_update: Can't put in empty key\n");
|
||||
@@ -335,6 +363,8 @@ ZEND_API int zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (flag & HASH_NEXT_INSERT) {
|
||||
h = ht->nNextFreeElement;
|
||||
}
|
||||
@@ -437,6 +467,7 @@ ZEND_API int zend_hash_pointer_update(HashTable *ht, char *arKey, uint nKeyLengt
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (nKeyLength <= 0) {
|
||||
#if ZEND_DEBUG
|
||||
@@ -515,6 +546,8 @@ ZEND_API int zend_hash_pointer_index_update_or_next_insert(HashTable *ht, ulong
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (flag & HASH_NEXT_INSERT) {
|
||||
h = ht->nNextFreeElement;
|
||||
}
|
||||
@@ -591,6 +624,8 @@ ZEND_API int zend_hash_is_pointer(HashTable *ht, char *arKey, uint nKeyLength)
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (nKeyLength <= 0) {
|
||||
#if ZEND_DEBUG
|
||||
ZEND_PUTS("zend_hash_update: Can't check for empty key\n");
|
||||
@@ -620,6 +655,8 @@ ZEND_API int zend_hash_index_is_pointer(HashTable *ht, ulong h)
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
nIndex = h % ht->nTableSize;
|
||||
|
||||
p = ht->arBuckets[nIndex];
|
||||
@@ -637,6 +674,8 @@ static int if_full_do_resize(HashTable *ht)
|
||||
{
|
||||
Bucket **t;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if ((ht->nNumOfElements > ht->nTableSize) && (ht->nHashSizeIndex < nNumPrimeNumbers - 1)) { /* Let's double the table
|
||||
size */
|
||||
t = (Bucket **) perealloc_recoverable(ht->arBuckets, PrimeNumbers[ht->nHashSizeIndex + 1] * sizeof(Bucket *),ht->persistent);
|
||||
@@ -659,6 +698,8 @@ ZEND_API int zend_hash_rehash(HashTable *ht)
|
||||
Bucket *p;
|
||||
uint nIndex;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
memset(ht->arBuckets, 0, PrimeNumbers[ht->nHashSizeIndex] * sizeof(Bucket *));
|
||||
p = ht->pListHead;
|
||||
while (p != NULL) {
|
||||
@@ -675,6 +716,8 @@ ZEND_API int zend_hash_del_key_or_index(HashTable *ht, char *arKey, uint nKeyLen
|
||||
uint nIndex;
|
||||
Bucket *p, *t = NULL; /* initialize just to shut gcc up with -Wall */
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (flag == HASH_DEL_KEY) {
|
||||
HANDLE_NUMERIC(arKey,nKeyLength,zend_hash_del_key_or_index(ht,arKey,nKeyLength,idx,HASH_DEL_INDEX));
|
||||
h = ht->pHashFunction(arKey, nKeyLength);
|
||||
@@ -730,6 +773,12 @@ ZEND_API void zend_hash_destroy(HashTable *ht)
|
||||
Bucket *p, *q;
|
||||
int delete_bucket;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
ht->inconsistent=1;
|
||||
#endif
|
||||
|
||||
p = ht->pListHead;
|
||||
while (p != NULL) {
|
||||
q = p;
|
||||
@@ -751,6 +800,10 @@ ZEND_API void zend_hash_destroy(HashTable *ht)
|
||||
}
|
||||
}
|
||||
pefree(ht->arBuckets,ht->persistent);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
ht->inconsistent=2;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -758,6 +811,12 @@ ZEND_API void zend_hash_clean(HashTable *ht)
|
||||
{
|
||||
Bucket *p, *q;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
ht->inconsistent=3;
|
||||
#endif
|
||||
|
||||
p = ht->pListHead;
|
||||
while (p != NULL) {
|
||||
q = p;
|
||||
@@ -778,6 +837,10 @@ ZEND_API void zend_hash_clean(HashTable *ht)
|
||||
ht->nNumOfElements = 0;
|
||||
ht->nNextFreeElement = 0;
|
||||
ht->pInternalPointer = NULL;
|
||||
|
||||
#if ZEND_DEBUG
|
||||
ht->inconsistent=0; /* OK - consistent again! */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -789,6 +852,8 @@ ZEND_API void zend_hash_apply(HashTable *ht,int (*destruct) (void *))
|
||||
{
|
||||
Bucket *p, *q;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
p = ht->pListHead;
|
||||
while (p != NULL) {
|
||||
q = p;
|
||||
@@ -808,6 +873,8 @@ ZEND_API void zend_hash_apply_with_argument(HashTable *ht,int (*destruct) (void
|
||||
{
|
||||
Bucket *p, *q;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
p = ht->pListHead;
|
||||
while (p != NULL) {
|
||||
q = p;
|
||||
@@ -829,6 +896,8 @@ ZEND_API void zend_hash_apply_with_arguments(HashTable *ht,int (*destruct)(void
|
||||
va_list args;
|
||||
zend_hash_key hash_key;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
va_start(args, num_args);
|
||||
|
||||
p = ht->pListHead;
|
||||
@@ -856,6 +925,9 @@ ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, void (*pCopyC
|
||||
{
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(source);
|
||||
IS_CONSISTENT(target);
|
||||
|
||||
p = source->pListHead;
|
||||
while (p) {
|
||||
memcpy(tmp, p->pData, size);
|
||||
@@ -879,6 +951,9 @@ ZEND_API void zend_hash_merge(HashTable *target, HashTable *source, void (*pCopy
|
||||
void *t;
|
||||
int mode = (overwrite?HASH_UPDATE:HASH_ADD);
|
||||
|
||||
IS_CONSISTENT(source);
|
||||
IS_CONSISTENT(target);
|
||||
|
||||
p = source->pListHead;
|
||||
while (p) {
|
||||
memcpy(tmp, p->pData, size);
|
||||
@@ -899,6 +974,8 @@ ZEND_API void zend_hash_merge(HashTable *target, HashTable *source, void (*pCopy
|
||||
|
||||
ZEND_API ulong zend_get_hash_value(HashTable *ht, char *arKey, uint nKeyLength)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
return ht->pHashFunction(arKey, nKeyLength);
|
||||
}
|
||||
|
||||
@@ -913,6 +990,8 @@ ZEND_API int zend_hash_find(HashTable *ht, char *arKey, uint nKeyLength, void **
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht,idx,pData));
|
||||
|
||||
h = ht->pHashFunction(arKey, nKeyLength);
|
||||
@@ -937,6 +1016,8 @@ ZEND_API int zend_hash_quick_find(HashTable *ht, char *arKey, uint nKeyLength, u
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
nIndex = h % ht->nTableSize;
|
||||
|
||||
p = ht->arBuckets[nIndex];
|
||||
@@ -959,6 +1040,8 @@ ZEND_API int zend_hash_exists(HashTable *ht, char *arKey, uint nKeyLength)
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht,idx));
|
||||
|
||||
h = ht->pHashFunction(arKey, nKeyLength);
|
||||
@@ -982,6 +1065,8 @@ ZEND_API int zend_hash_index_find(HashTable *ht, ulong h, void **pData)
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
nIndex = h % ht->nTableSize;
|
||||
|
||||
p = ht->arBuckets[nIndex];
|
||||
@@ -1001,6 +1086,8 @@ ZEND_API int zend_hash_index_exists(HashTable *ht, ulong h)
|
||||
uint nIndex;
|
||||
Bucket *p;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
nIndex = h % ht->nTableSize;
|
||||
|
||||
p = ht->arBuckets[nIndex];
|
||||
@@ -1016,12 +1103,16 @@ ZEND_API int zend_hash_index_exists(HashTable *ht, ulong h)
|
||||
|
||||
ZEND_API int zend_hash_num_elements(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
return ht->nNumOfElements;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API void zend_hash_internal_pointer_reset(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
ht->pInternalPointer = ht->pListHead;
|
||||
}
|
||||
|
||||
@@ -1031,12 +1122,16 @@ ZEND_API void zend_hash_internal_pointer_reset(HashTable *ht)
|
||||
*/
|
||||
ZEND_API void zend_hash_internal_pointer_end(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
ht->pInternalPointer = ht->pListTail;
|
||||
}
|
||||
|
||||
|
||||
ZEND_API void zend_hash_move_forward(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (ht->pInternalPointer) {
|
||||
ht->pInternalPointer = ht->pInternalPointer->pListNext;
|
||||
}
|
||||
@@ -1044,6 +1139,8 @@ ZEND_API void zend_hash_move_forward(HashTable *ht)
|
||||
|
||||
ZEND_API void zend_hash_move_backwards(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (ht->pInternalPointer) {
|
||||
ht->pInternalPointer = ht->pInternalPointer->pListLast;
|
||||
}
|
||||
@@ -1055,6 +1152,8 @@ ZEND_API int zend_hash_get_current_key(HashTable *ht, char **str_index, ulong *n
|
||||
{
|
||||
Bucket *p = ht->pInternalPointer;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (p) {
|
||||
if (p->nKeyLength) {
|
||||
*str_index = (char *) pemalloc(p->nKeyLength,ht->persistent);
|
||||
@@ -1073,6 +1172,8 @@ ZEND_API int zend_hash_get_current_key_type(HashTable *ht)
|
||||
{
|
||||
Bucket *p = ht->pInternalPointer;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (p) {
|
||||
if (p->nKeyLength) {
|
||||
return HASH_KEY_IS_STRING;
|
||||
@@ -1088,6 +1189,8 @@ ZEND_API int zend_hash_get_current_data(HashTable *ht, void **pData)
|
||||
{
|
||||
Bucket *p = ht->pInternalPointer;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (p) {
|
||||
*pData = p->pData;
|
||||
return SUCCESS;
|
||||
@@ -1104,6 +1207,8 @@ ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
|
||||
Bucket *p;
|
||||
int i, j;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (ht->nNumOfElements <= 1) { /* Doesn't require sorting */
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -1156,6 +1261,8 @@ ZEND_API int zend_hash_minmax(HashTable *ht, int (*compar) (const void *, const
|
||||
{
|
||||
Bucket *p,*res;
|
||||
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
if (ht->nNumOfElements == 0 ) {
|
||||
*pData=NULL;
|
||||
return FAILURE;
|
||||
@@ -1179,6 +1286,8 @@ ZEND_API int zend_hash_minmax(HashTable *ht, int (*compar) (const void *, const
|
||||
|
||||
ZEND_API ulong zend_hash_next_free_element(HashTable *ht)
|
||||
{
|
||||
IS_CONSISTENT(ht);
|
||||
|
||||
return ht->nNextFreeElement;
|
||||
|
||||
}
|
||||
|
||||
@@ -60,6 +60,9 @@ typedef struct hashtable {
|
||||
Bucket **arBuckets;
|
||||
int (*pDestructor) (void *pData);
|
||||
unsigned char persistent;
|
||||
#if ZEND_DEBUG
|
||||
int inconsistent;
|
||||
#endif
|
||||
} HashTable;
|
||||
|
||||
typedef int (*compare_func_t) (const void *, const void *);
|
||||
|
||||
Reference in New Issue
Block a user