Patch rand_hash_resize.patch for *General Issues Bug #60655
Patch version 2012-01-05 08:09 UTC
Return to Bug #60655 |
Download this patch
Patch Revisions:
Developer: laruence@php.net
Index: Zend/zend_string.c
===================================================================
--- Zend/zend_string.c (revision 321772)
+++ Zend/zend_string.c (working copy)
@@ -91,7 +91,7 @@
}
h = zend_inline_hash_func(arKey, nKeyLength);
- nIndex = h & CG(interned_strings).nTableMask;
+ nIndex = h % (CG(interned_strings).nTableMask + 1);
p = CG(interned_strings).arBuckets[nIndex];
while (p != NULL) {
if ((p->h == h) && (p->nKeyLength == nKeyLength)) {
Index: Zend/zend_hash.c
===================================================================
--- Zend/zend_hash.c (revision 321772)
+++ Zend/zend_hash.c (working copy)
@@ -21,6 +21,13 @@
#include "zend.h"
#include "zend_globals.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
#define CONNECT_TO_BUCKET_DLLIST(element, list_head) \
(element)->pNext = (list_head); \
@@ -43,6 +50,8 @@
(ht)->pInternalPointer = (element); \
}
+#define GET_INDEX_OFFSET(ht, h) ((h) % ((ht)->nTableMask + 1))
+
#if ZEND_DEBUG
#define HT_OK 0
#define HT_IS_DESTROYING 1
@@ -145,6 +154,65 @@
static const Bucket *uninitialized_bucket = NULL;
+static void zend_hash_random(unsigned char *buf, size_t size)
+{
+ size_t i = 0;
+ unsigned char t;
+
+#ifdef ZEND_WIN32
+ HCRYPTPROV hCryptProv;
+ int has_context = 0;
+
+ if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
+ /* Could mean that the key container does not exist, let try
+ again by asking for a new one */
+ if (GetLastError() == NTE_BAD_KEYSET) {
+ if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
+ has_context = 1;
+ }
+ }
+ } else {
+ has_context = 1;
+ }
+ if (has_context) {
+ do {
+ BOOL ret = CryptGenRandom(hCryptProv, size, buf);
+ CryptReleaseContext(hCryptProv, 0);
+ if (ret) {
+ while (i < size && buf[i] != 0) {
+ i++;
+ }
+ if (i == size) {
+ return;
+ }
+ }
+ } while (0);
+ }
+#elif defined(HAVE_DEV_URANDOM)
+ int fd = open("/dev/urandom", 0);
+
+ if (fd >= 0) {
+ if (read(fd, buf, size) == size) {
+ while (i < size && buf[i] != 0) {
+ i++;
+ }
+ if (i == size) {
+ close(fd);
+ return;
+ }
+ }
+ close(fd);
+ }
+#endif
+ t = (unsigned char)getpid();
+ while (i < size) {
+ do {
+ buf[i] = ((unsigned char)rand()) ^ t;
+ } while (buf[i] == 0);
+ t = buf[i++] << 1;
+ }
+}
+
ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
{
uint i = 3;
@@ -213,7 +281,7 @@
CHECK_INIT(ht);
h = zend_inline_hash_func(arKey, nKeyLength);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -290,7 +358,7 @@
}
CHECK_INIT(ht);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -378,7 +446,7 @@
if (flag & HASH_NEXT_INSERT) {
h = ht->nNextFreeElement;
}
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -440,19 +508,22 @@
static int zend_hash_do_resize(HashTable *ht)
{
Bucket **t;
+ uint size, r;
#ifdef ZEND_SIGNALS
TSRMLS_FETCH();
#endif
IS_CONSISTENT(ht);
- if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */
- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent);
+ zend_hash_random((unsigned char *)&r, sizeof(uint));
+ size = (ht->nTableSize << 1) + (r & ht->nTableMask);
+ if (size > 0) {
+ t = (Bucket **) perealloc_recoverable(ht->arBuckets, (size) * sizeof(Bucket *), ht->persistent);
if (t) {
HANDLE_BLOCK_INTERRUPTIONS();
ht->arBuckets = t;
- ht->nTableSize = (ht->nTableSize << 1);
- ht->nTableMask = ht->nTableSize - 1;
+ ht->nTableSize = size;
+ ht->nTableMask = size - 1;
zend_hash_rehash(ht);
HANDLE_UNBLOCK_INTERRUPTIONS();
return SUCCESS;
@@ -475,7 +546,7 @@
memset(ht->arBuckets, 0, ht->nTableSize * sizeof(Bucket *));
p = ht->pListHead;
while (p != NULL) {
- nIndex = p->h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, p->h);
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[nIndex]);
ht->arBuckets[nIndex] = p;
p = p->pListNext;
@@ -496,7 +567,7 @@
if (flag == HASH_DEL_KEY) {
h = zend_inline_hash_func(arKey, nKeyLength);
}
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -620,7 +691,7 @@
} else {
uint nIndex;
- nIndex = p->h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, p->h);
ht->arBuckets[nIndex] = p->pNext;
}
if (p->pNext) {
@@ -919,7 +990,7 @@
IS_CONSISTENT(ht);
h = zend_inline_hash_func(arKey, nKeyLength);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -945,7 +1016,7 @@
IS_CONSISTENT(ht);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -969,7 +1040,7 @@
IS_CONSISTENT(ht);
h = zend_inline_hash_func(arKey, nKeyLength);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -994,7 +1065,7 @@
IS_CONSISTENT(ht);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -1016,7 +1087,7 @@
IS_CONSISTENT(ht);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -1037,7 +1108,7 @@
IS_CONSISTENT(ht);
- nIndex = h & ht->nTableMask;
+ nIndex = GET_INDEX_OFFSET(ht, h);
p = ht->arBuckets[nIndex];
while (p != NULL) {
@@ -1078,7 +1149,7 @@
Bucket *p;
IS_CONSISTENT(ht);
- p = ht->arBuckets[ptr->h & ht->nTableMask];
+ p = ht->arBuckets[GET_INDEX_OFFSET(ht, ptr->h)];
while (p != NULL) {
if (p == ptr->pos) {
ht->pInternalPointer = p;
@@ -1229,7 +1300,7 @@
return SUCCESS;
}
- q = ht->arBuckets[num_index & ht->nTableMask];
+ q = ht->arBuckets[GET_INDEX_OFFSET(ht, num_index)];
while (q != NULL) {
if (!q->nKeyLength && q->h == num_index) {
break;
@@ -1250,7 +1321,7 @@
return SUCCESS;
}
- q = ht->arBuckets[h & ht->nTableMask];
+ q = ht->arBuckets[GET_INDEX_OFFSET(ht, h)];
while (q != NULL) {
if (q->arKey == str_index ||
@@ -1280,8 +1351,8 @@
}
if (mode & found) {
/* delete current bucket */
- if (p == ht->arBuckets[p->h & ht->nTableMask]) {
- ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
+ if (p == ht->arBuckets[GET_INDEX_OFFSET(ht, p->h)]) {
+ ht->arBuckets[GET_INDEX_OFFSET(ht, p->h)] = p->pNext;
} else {
p->pLast->pNext = p->pNext;
}
@@ -1315,8 +1386,8 @@
}
}
/* delete another bucket with the same key */
- if (q == ht->arBuckets[q->h & ht->nTableMask]) {
- ht->arBuckets[q->h & ht->nTableMask] = q->pNext;
+ if (q == ht->arBuckets[GET_INDEX_OFFSET(ht, q->h)]) {
+ ht->arBuckets[GET_INDEX_OFFSET(ht, q->h)] = q->pNext;
} else {
q->pLast->pNext = q->pNext;
}
@@ -1353,7 +1424,7 @@
if (p->pLast) {
p->pLast->pNext = p->pNext;
} else {
- ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
+ ht->arBuckets[GET_INDEX_OFFSET(ht, p->h)] = p->pNext;
}
if ((IS_INTERNED(p->arKey) != IS_INTERNED(str_index)) ||
@@ -1408,8 +1479,8 @@
}
}
- CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]);
- ht->arBuckets[p->h & ht->nTableMask] = p;
+ CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[GET_INDEX_OFFSET(ht, p->h)]);
+ ht->arBuckets[GET_INDEX_OFFSET(ht, p->h)] = p;
HANDLE_UNBLOCK_INTERRUPTIONS();
return SUCCESS;
Index: main/php_globals.h
===================================================================
--- main/php_globals.h (revision 321772)
+++ main/php_globals.h (working copy)
@@ -146,7 +146,6 @@
zend_bool com_initialized;
#endif
long max_input_nesting_level;
- long max_input_vars;
zend_bool in_user_include;
char *user_ini_filename;
Index: main/php_variables.c
===================================================================
--- main/php_variables.c (revision 321772)
+++ main/php_variables.c (working copy)
@@ -178,15 +178,10 @@
} else {
escaped_index = index;
if (zend_symtable_find(symtable1, escaped_index, index_len + 1, (void **) &gpc_element_p) == FAILURE
- || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
- if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
- if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
- }
- MAKE_STD_ZVAL(gpc_element);
- array_init(gpc_element);
- zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
- }
+ || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
+ MAKE_STD_ZVAL(gpc_element);
+ array_init(gpc_element);
+ zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
}
if (index != escaped_index) {
efree(escaped_index);
@@ -225,14 +220,7 @@
zend_symtable_exists(symtable1, escaped_index, index_len + 1)) {
zval_ptr_dtor(&gpc_element);
} else {
- if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
- if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
- }
- zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
- } else {
- zval_ptr_dtor(&gpc_element);
- }
+ zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
}
if (escaped_index != index) {
efree(escaped_index);
Index: main/main.c
===================================================================
--- main/main.c (revision 321772)
+++ main/main.c (working copy)
@@ -531,7 +531,6 @@
STD_PHP_INI_ENTRY("post_max_size", "8M", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, post_max_size, sapi_globals_struct,sapi_globals)
STD_PHP_INI_ENTRY("upload_tmp_dir", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, upload_tmp_dir, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("max_input_nesting_level", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLongGEZero, max_input_nesting_level, php_core_globals, core_globals)
- STD_PHP_INI_ENTRY("max_input_vars", "1000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLongGEZero, max_input_vars, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("user_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, user_dir, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("variables_order", "EGPCS", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateStringUnempty, variables_order, php_core_globals, core_globals)
|