Skip to content

Commit d9c1a38

Browse files
committed
Fixed bug #28072 (static array with some constant keys will be incorrectly ordered).
1 parent 3c5b9a6 commit d9c1a38

File tree

5 files changed

+158
-4
lines changed

5 files changed

+158
-4
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ PHP NEWS
3434
- Fixed bug #30096 (gmmktime does not return the corrent time). (Derick)
3535
- Fixed bug #30052 (Crash on shutdown after odbc_pconnect()). (Edin)
3636
- Fixed bug #28377 (debug_backtrace is intermittently passing args). (Dmitry)
37+
- Fixed bug #28072 (static array with some constant keys will be incorrectly
38+
ordered). (Dmitry)
3739
- Fixed bug #27268 (Bad references accentuated by clone). (Dmitry)
3840

3941
22 Jun 2005, PHP 5.1 Beta 2

Zend/tests/bug28072.phpt

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
Bug #28072 (static array with some constant keys will be incorrectly ordered)
3+
--FILE--
4+
<?php
5+
define("FIRST_KEY", "a");
6+
define("THIRD_KEY", "c");
7+
8+
9+
function test()
10+
{
11+
static $arr = array(
12+
FIRST_KEY => "111",
13+
"b" => "222",
14+
THIRD_KEY => "333",
15+
"d" => "444"
16+
);
17+
print_r($arr);
18+
}
19+
20+
function test2()
21+
{
22+
static $arr = array(
23+
FIRST_KEY => "111",
24+
"a" => "222",
25+
"c" => "333",
26+
THIRD_KEY => "444"
27+
);
28+
print_r($arr);
29+
}
30+
31+
test();
32+
test2();
33+
?>
34+
--EXPECT--
35+
Array
36+
(
37+
[a] => 111
38+
[b] => 222
39+
[c] => 333
40+
[d] => 444
41+
)
42+
Array
43+
(
44+
[a] => 111
45+
[c] => 444
46+
)

Zend/zend_execute_API.c

+20-4
Original file line numberDiff line numberDiff line change
@@ -490,17 +490,33 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC)
490490

491491
/* preserve this bit for inheritance */
492492
Z_TYPE_PP(element) |= IS_CONSTANT_INDEX;
493+
zval_ptr_dtor(element);
494+
*element = new_val;
493495

494496
switch (const_value.type) {
495-
case IS_STRING:
496-
zend_symtable_update(p->value.ht, const_value.value.str.val, const_value.value.str.len+1, &new_val, sizeof(zval *), NULL);
497+
case IS_STRING: {
498+
long lval;
499+
double dval;
500+
501+
if (is_numeric_string(const_value.value.str.val, const_value.value.str.len, &lval, &dval, 0) == IS_LONG) {
502+
zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, lval);
503+
} else {
504+
zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_STRING, const_value.value.str.val, const_value.value.str.len+1, 0);
505+
}
497506
break;
507+
}
498508
case IS_BOOL:
499509
case IS_LONG:
500-
zend_hash_index_update(p->value.ht, const_value.value.lval, &new_val, sizeof(zval *), NULL);
510+
zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, const_value.value.lval);
511+
break;
512+
case IS_DOUBLE:
513+
zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_LONG, NULL, 0, (long)const_value.value.dval);
514+
break;
515+
case IS_NULL:
516+
zend_hash_update_current_key(p->value.ht, HASH_KEY_IS_STRING, "", 1, 0);
501517
break;
502518
}
503-
zend_hash_del(p->value.ht, str_index, str_index_len);
519+
zend_hash_move_forward(p->value.ht);
504520
zval_dtor(&const_value);
505521
}
506522
zend_hash_apply_with_argument(p->value.ht, (apply_func_arg_t) zval_update_constant, (void *) 1 TSRMLS_CC);

Zend/zend_hash.c

+87
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,93 @@ ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosi
11061106
}
11071107
}
11081108

1109+
/* This function changes key of currevt element without changing elements'
1110+
* order. If element with target key already exists, it will be deleted first.
1111+
*/
1112+
ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, char *str_index, uint str_length, ulong num_index, HashPosition *pos)
1113+
{
1114+
Bucket *p;
1115+
1116+
p = pos ? (*pos) : ht->pInternalPointer;
1117+
1118+
IS_CONSISTENT(ht);
1119+
1120+
if (p) {
1121+
if (key_type == HASH_KEY_IS_LONG) {
1122+
str_length = 0;
1123+
if (!p->nKeyLength && p->h == num_index) {
1124+
return SUCCESS;
1125+
}
1126+
zend_hash_index_del(ht, num_index);
1127+
} else if (key_type == HASH_KEY_IS_STRING) {
1128+
if (p->nKeyLength == str_length &&
1129+
memcmp(p->arKey, str_index, str_length) == 0) {
1130+
return SUCCESS;
1131+
}
1132+
zend_hash_del(ht, str_index, str_length);
1133+
} else {
1134+
return FAILURE;
1135+
}
1136+
1137+
HANDLE_BLOCK_INTERRUPTIONS();
1138+
1139+
if (p->pNext) {
1140+
p->pNext->pLast = p->pLast;
1141+
}
1142+
if (p->pLast) {
1143+
p->pLast->pNext = p->pNext;
1144+
} else{
1145+
ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
1146+
}
1147+
1148+
if (p->nKeyLength != str_length) {
1149+
Bucket *q = (Bucket *) pemalloc(sizeof(Bucket) - 1 + str_length, ht->persistent);
1150+
1151+
q->nKeyLength = str_length;
1152+
if (p->pData == &p->pDataPtr) {
1153+
q->pData = &q->pDataPtr;
1154+
} else {
1155+
q->pData = p->pData;
1156+
}
1157+
q->pDataPtr = p->pDataPtr;
1158+
q->pListNext = p->pListNext;
1159+
q->pListLast = p->pListLast;
1160+
if (q->pListNext) {
1161+
p->pListNext->pListLast = q;
1162+
} else {
1163+
ht->pListTail = q;
1164+
}
1165+
if (q->pListLast) {
1166+
p->pListLast->pListNext = q;
1167+
} else {
1168+
ht->pListHead = q;
1169+
}
1170+
if (ht->pInternalPointer == p) {
1171+
ht->pInternalPointer = q;
1172+
}
1173+
if (pos) {
1174+
*pos = q;
1175+
}
1176+
pefree(p, ht->persistent);
1177+
p = q;
1178+
}
1179+
1180+
if (key_type == HASH_KEY_IS_LONG) {
1181+
p->h = num_index;
1182+
} else {
1183+
memcpy(p->arKey, str_index, str_length);
1184+
p->h = zend_inline_hash_func(str_index, str_length);
1185+
}
1186+
1187+
CONNECT_TO_BUCKET_DLLIST(p, ht->arBuckets[p->h & ht->nTableMask]);
1188+
ht->arBuckets[p->h & ht->nTableMask] = p;
1189+
HANDLE_UNBLOCK_INTERRUPTIONS();
1190+
1191+
return SUCCESS;
1192+
} else {
1193+
return FAILURE;
1194+
}
1195+
}
11091196

11101197
ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func,
11111198
compare_func_t compar, int renumber TSRMLS_DC)

Zend/zend_hash.h

+3
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos)
174174
ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos);
175175
ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
176176
ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
177+
ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, char *str_index, uint str_length, ulong num_index, HashPosition *pos);
177178

178179
#define zend_hash_has_more_elements(ht) \
179180
zend_hash_has_more_elements_ex(ht, NULL)
@@ -191,6 +192,8 @@ ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos
191192
zend_hash_internal_pointer_reset_ex(ht, NULL)
192193
#define zend_hash_internal_pointer_end(ht) \
193194
zend_hash_internal_pointer_end_ex(ht, NULL)
195+
#define zend_hash_update_current_key(ht, key_type, str_index, str_length, num_index) \
196+
zend_hash_update_current_key_ex(ht, key_type, str_index, str_length, num_index, NULL)
194197

195198
/* Copying, merging and sorting */
196199
ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size);

0 commit comments

Comments
 (0)