summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-04-01 14:20:59 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-04-01 14:20:59 +0200
commit14b770d4074616f7f5dcf026422a91a8b7419d90 (patch)
treec814445c60ffcb0638789f182029bff23b5be8a3
parentcc3af6fdeaa2c307244499017f7ae4f10f853efc (diff)
downloadphp-git-14b770d4074616f7f5dcf026422a91a8b7419d90.tar.gz
Fix literal compaction collision between string and double
For the sake of simplicity I'm using a separate hashtable, rather than trying to do hash perturabation on the double strings.
-rw-r--r--ext/opcache/Optimizer/compact_literals.c11
-rw-r--r--ext/opcache/tests/compact_literals_collision.phptbin0 -> 252 bytes
2 files changed, 8 insertions, 3 deletions
diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c
index fdab0068a4..e4dab13b9c 100644
--- a/ext/opcache/Optimizer/compact_literals.c
+++ b/ext/opcache/Optimizer/compact_literals.c
@@ -125,7 +125,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
int l_false = -1;
int l_true = -1;
int l_empty_arr = -1;
- HashTable hash;
+ HashTable hash, double_hash;
zend_string *key = NULL;
void *checkpoint = zend_arena_checkpoint(ctx->arena);
int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot;
@@ -329,6 +329,8 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
/* Merge equal constants */
j = 0;
zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0);
+ /* Use separate hashtable for doubles stored as string keys, to avoid collisions. */
+ zend_hash_init(&double_hash, 0, NULL, NULL, 0);
map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int));
memset(map, 0, op_array->last_literal * sizeof(int));
for (i = 0; i < op_array->last_literal; i++) {
@@ -411,12 +413,12 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
}
break;
case IS_DOUBLE:
- if ((pos = zend_hash_str_find(&hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double))) != NULL) {
+ if ((pos = zend_hash_str_find(&double_hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double))) != NULL) {
map[i] = Z_LVAL_P(pos);
} else {
map[i] = j;
ZVAL_LONG(&zv, j);
- zend_hash_str_add(&hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double), &zv);
+ zend_hash_str_add(&double_hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double), &zv);
if (i != j) {
op_array->literals[j] = op_array->literals[i];
info[j] = info[i];
@@ -494,7 +496,10 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
break;
}
}
+
+ /* Only clean "hash", as it will be reused in the loop below. */
zend_hash_clean(&hash);
+ zend_hash_destroy(&double_hash);
op_array->last_literal = j;
const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int));
diff --git a/ext/opcache/tests/compact_literals_collision.phpt b/ext/opcache/tests/compact_literals_collision.phpt
new file mode 100644
index 0000000000..b7226b40f5
--- /dev/null
+++ b/ext/opcache/tests/compact_literals_collision.phpt
Binary files differ