Skip to content

Commit a40a69f

Browse files
committed
Merge branch 'PHP-7.4'
* PHP-7.4: Introduce extra counter to avoid RTD key collisions
2 parents 01875e8 + 0f2cdbf commit a40a69f

File tree

4 files changed

+37
-33
lines changed

4 files changed

+37
-33
lines changed

Zend/zend.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ static void zend_set_default_compile_time_values(void) /* {{{ */
524524
/* default compile-time values */
525525
CG(short_tags) = short_tags_default;
526526
CG(compiler_options) = compiler_options_default;
527+
528+
CG(rtd_key_counter) = 0;
527529
}
528530
/* }}} */
529531

Zend/zend_compile.c

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,11 @@ static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
132132
}
133133
/* }}} */
134134

135-
static zend_string *zend_build_runtime_definition_key(zend_string *name, unsigned char *lex_pos) /* {{{ */
135+
static zend_string *zend_build_runtime_definition_key(zend_string *name, uint32_t start_lineno) /* {{{ */
136136
{
137-
zend_string *result;
138-
char char_pos_buf[32];
139-
size_t char_pos_len = sprintf(char_pos_buf, "%p", lex_pos);
140137
zend_string *filename = CG(active_op_array)->filename;
141-
142-
/* NULL, name length, filename length, last accepting char position length */
143-
result = zend_string_alloc(1 + ZSTR_LEN(name) + ZSTR_LEN(filename) + char_pos_len, 0);
144-
sprintf(ZSTR_VAL(result), "%c%s%s%s", '\0', ZSTR_VAL(name), ZSTR_VAL(filename), char_pos_buf);
138+
zend_string *result = zend_strpprintf(0, "%c%s%s:%" PRIu32 "$%" PRIx32,
139+
'\0', ZSTR_VAL(name), ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
145140
return zend_new_interned_string(result);
146141
}
147142
/* }}} */
@@ -6124,8 +6119,11 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
61246119
return;
61256120
}
61266121

6127-
key = zend_build_runtime_definition_key(lcname, decl->lex_pos);
6128-
zend_hash_update_ptr(CG(function_table), key, op_array);
6122+
key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
6123+
if (!zend_hash_add_ptr(CG(function_table), key, op_array)) {
6124+
zend_error_noreturn(E_ERROR,
6125+
"Runtime definition key collision for function %s. This is a bug", ZSTR_VAL(name));
6126+
}
61296127

61306128
if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
61316129
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
@@ -6529,16 +6527,11 @@ void zend_compile_implements(zend_ast *ast) /* {{{ */
65296527
}
65306528
/* }}} */
65316529

6532-
static zend_string *zend_generate_anon_class_name(unsigned char *lex_pos) /* {{{ */
6530+
static zend_string *zend_generate_anon_class_name(uint32_t start_lineno) /* {{{ */
65336531
{
6534-
zend_string *result;
6535-
char char_pos_buf[32];
6536-
size_t char_pos_len = sprintf(char_pos_buf, "%p", lex_pos);
65376532
zend_string *filename = CG(active_op_array)->filename;
6538-
6539-
/* NULL, name length, filename length, last accepting char position length */
6540-
result = zend_string_alloc(sizeof("class@anonymous") + ZSTR_LEN(filename) + char_pos_len, 0);
6541-
sprintf(ZSTR_VAL(result), "class@anonymous%c%s%s", '\0', ZSTR_VAL(filename), char_pos_buf);
6533+
zend_string *result = zend_strpprintf(0, "class@anonymous%c%s:%" PRIu32 "$%" PRIx32,
6534+
'\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
65426535
return zend_new_interned_string(result);
65436536
}
65446537
/* }}} */
@@ -6578,7 +6571,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
65786571

65796572
zend_register_seen_symbol(lcname, ZEND_SYMBOL_CLASS);
65806573
} else {
6581-
name = zend_generate_anon_class_name(decl->lex_pos);
6574+
name = zend_generate_anon_class_name(decl->start_lineno);
65826575
lcname = zend_string_tolower(name);
65836576
}
65846577
lcname = zend_new_interned_string(lcname);
@@ -6728,20 +6721,19 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
67286721
opline->extended_value = zend_alloc_cache_slot();
67296722
opline->result_type = IS_VAR;
67306723
opline->result.var = get_temporary_variable();
6731-
67326724
if (!zend_hash_add_ptr(CG(class_table), lcname, ce)) {
6733-
/* this anonymous class has been included */
6734-
zval zv;
6735-
ZVAL_PTR(&zv, ce);
6736-
destroy_zend_class(&zv);
6737-
return opline;
6725+
zend_error_noreturn(E_ERROR,
6726+
"Runtime definition key collision for %s. This is a bug", ZSTR_VAL(name));
67386727
}
67396728
} else {
6740-
zend_string *key = zend_build_runtime_definition_key(lcname, decl->lex_pos);
6729+
zend_string *key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
67416730

67426731
/* RTD key is placed after lcname literal in op1 */
67436732
zend_add_literal_string(&key);
6744-
zend_hash_update_ptr(CG(class_table), key, ce);
6733+
if (!zend_hash_add_ptr(CG(class_table), key, ce)) {
6734+
zend_error_noreturn(E_ERROR,
6735+
"Runtime definition key collision for class %s. This is a bug", ZSTR_VAL(name));
6736+
}
67456737

67466738
opline->opcode = ZEND_DECLARE_CLASS;
67476739
if (extends_ast && toplevel

Zend/zend_globals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ struct _zend_compiler_globals {
127127

128128
HashTable *delayed_variance_obligations;
129129
HashTable *delayed_autoloads;
130+
131+
uint32_t rtd_key_counter;
130132
};
131133

132134

ext/opcache/zend_accelerator_util_funcs.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,16 @@ static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
439439
t = zend_hash_find_ex(target, p->key, 1);
440440
if (UNEXPECTED(t != NULL)) {
441441
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
442-
/* Mangled key */
443-
t = zend_hash_update(target, p->key, &p->val);
442+
/* Runtime definition key. There are two circumstances under which the key can
443+
* already be defined:
444+
* 1. The file has been re-included without being changed in the meantime. In
445+
* this case we can keep the old value, because we know that the definition
446+
* hasn't changed.
447+
* 2. The file has been changed in the meantime, but the RTD key ends up colliding.
448+
* This would be a bug.
449+
* As we can't distinguish these cases, we assume that it is 1. and keep the old
450+
* value. */
451+
continue;
444452
} else {
445453
goto failure;
446454
}
@@ -483,8 +491,8 @@ static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable
483491
t = zend_hash_find_ex(target, p->key, 1);
484492
if (UNEXPECTED(t != NULL)) {
485493
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
486-
/* Mangled key */
487-
zend_hash_update_ptr(target, p->key, Z_PTR(p->val));
494+
/* See comment in zend_accel_function_hash_copy(). */
495+
continue;
488496
} else {
489497
goto failure;
490498
}
@@ -526,7 +534,7 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source)
526534
t = zend_hash_find_ex(target, p->key, 1);
527535
if (UNEXPECTED(t != NULL)) {
528536
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
529-
/* Mangled key - ignore and wait for runtime */
537+
/* See comment in zend_accel_function_hash_copy(). */
530538
continue;
531539
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
532540
zend_class_entry *ce1 = Z_PTR(p->val);
@@ -563,7 +571,7 @@ static void zend_accel_class_hash_copy_from_shm(HashTable *target, HashTable *so
563571
t = zend_hash_find_ex(target, p->key, 1);
564572
if (UNEXPECTED(t != NULL)) {
565573
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
566-
/* Mangled key - ignore and wait for runtime */
574+
/* See comment in zend_accel_function_hash_copy(). */
567575
continue;
568576
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
569577
zend_class_entry *ce1 = Z_PTR(p->val);

0 commit comments

Comments
 (0)