]> granicus.if.org Git - php/commitdiff
if ZEND_DEBUG mode is on we'll now see warnings when a HashTable is accessed
authorThies C. Arntzen <thies@php.net>
Sat, 15 Jan 2000 13:40:17 +0000 (13:40 +0000)
committerThies C. Arntzen <thies@php.net>
Sat, 15 Jan 2000 13:40:17 +0000 (13:40 +0000)
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!

Zend/zend_hash.c
Zend/zend_hash.h

index 9eb2b6cf9795acd973c6cbf5f839fbcc39ecfd2e..795c66f474c108a5e59f40d67d0f4e467761d13a 100644 (file)
        } 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;
 
 }
index dc2a469a54fee500a1ca5a0f22d98943150b98e2..feefc731056f35957ce45e08c47f7f0195491025 100644 (file)
@@ -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 *);