summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThies C. Arntzen <thies@php.net>2000-01-15 13:40:17 +0000
committerThies C. Arntzen <thies@php.net>2000-01-15 13:40:17 +0000
commitc93a18902813679776c482b352fb20f3e430a1cd (patch)
tree3e0fa9597450341ad1915836fdcacd678028b167
parentbf4d20aaa892bc5246a6bf84c41a34bf0a7b2e78 (diff)
downloadphp-git-c93a18902813679776c482b352fb20f3e430a1cd.tar.gz
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!
-rw-r--r--Zend/zend_hash.c109
-rw-r--r--Zend/zend_hash.h3
2 files changed, 112 insertions, 0 deletions
diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c
index 9eb2b6cf97..795c66f474 100644
--- a/Zend/zend_hash.c
+++ b/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;
}
diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h
index dc2a469a54..feefc73105 100644
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@ -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 *);