Merge branch 'PHP-7.4'

* PHP-7.4:
  Introduce extra counter to avoid RTD key collisions
This commit is contained in:
Nikita Popov 2019-12-13 11:05:41 +01:00
commit a40a69fdd0
4 changed files with 37 additions and 33 deletions

View file

@ -524,6 +524,8 @@ static void zend_set_default_compile_time_values(void) /* {{{ */
/* default compile-time values */ /* default compile-time values */
CG(short_tags) = short_tags_default; CG(short_tags) = short_tags_default;
CG(compiler_options) = compiler_options_default; CG(compiler_options) = compiler_options_default;
CG(rtd_key_counter) = 0;
} }
/* }}} */ /* }}} */

View file

@ -132,16 +132,11 @@ static void zend_destroy_property_info_internal(zval *zv) /* {{{ */
} }
/* }}} */ /* }}} */
static zend_string *zend_build_runtime_definition_key(zend_string *name, unsigned char *lex_pos) /* {{{ */ static zend_string *zend_build_runtime_definition_key(zend_string *name, uint32_t start_lineno) /* {{{ */
{ {
zend_string *result;
char char_pos_buf[32];
size_t char_pos_len = sprintf(char_pos_buf, "%p", lex_pos);
zend_string *filename = CG(active_op_array)->filename; zend_string *filename = CG(active_op_array)->filename;
zend_string *result = zend_strpprintf(0, "%c%s%s:%" PRIu32 "$%" PRIx32,
/* NULL, name length, filename length, last accepting char position length */ '\0', ZSTR_VAL(name), ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
result = zend_string_alloc(1 + ZSTR_LEN(name) + ZSTR_LEN(filename) + char_pos_len, 0);
sprintf(ZSTR_VAL(result), "%c%s%s%s", '\0', ZSTR_VAL(name), ZSTR_VAL(filename), char_pos_buf);
return zend_new_interned_string(result); return zend_new_interned_string(result);
} }
/* }}} */ /* }}} */
@ -6124,8 +6119,11 @@ static void zend_begin_func_decl(znode *result, zend_op_array *op_array, zend_as
return; return;
} }
key = zend_build_runtime_definition_key(lcname, decl->lex_pos); key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
zend_hash_update_ptr(CG(function_table), key, op_array); if (!zend_hash_add_ptr(CG(function_table), key, op_array)) {
zend_error_noreturn(E_ERROR,
"Runtime definition key collision for function %s. This is a bug", ZSTR_VAL(name));
}
if (op_array->fn_flags & ZEND_ACC_CLOSURE) { if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL); opline = zend_emit_op_tmp(result, ZEND_DECLARE_LAMBDA_FUNCTION, NULL, NULL);
@ -6529,16 +6527,11 @@ void zend_compile_implements(zend_ast *ast) /* {{{ */
} }
/* }}} */ /* }}} */
static zend_string *zend_generate_anon_class_name(unsigned char *lex_pos) /* {{{ */ static zend_string *zend_generate_anon_class_name(uint32_t start_lineno) /* {{{ */
{ {
zend_string *result;
char char_pos_buf[32];
size_t char_pos_len = sprintf(char_pos_buf, "%p", lex_pos);
zend_string *filename = CG(active_op_array)->filename; zend_string *filename = CG(active_op_array)->filename;
zend_string *result = zend_strpprintf(0, "class@anonymous%c%s:%" PRIu32 "$%" PRIx32,
/* NULL, name length, filename length, last accepting char position length */ '\0', ZSTR_VAL(filename), start_lineno, CG(rtd_key_counter)++);
result = zend_string_alloc(sizeof("class@anonymous") + ZSTR_LEN(filename) + char_pos_len, 0);
sprintf(ZSTR_VAL(result), "class@anonymous%c%s%s", '\0', ZSTR_VAL(filename), char_pos_buf);
return zend_new_interned_string(result); return zend_new_interned_string(result);
} }
/* }}} */ /* }}} */
@ -6578,7 +6571,7 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
zend_register_seen_symbol(lcname, ZEND_SYMBOL_CLASS); zend_register_seen_symbol(lcname, ZEND_SYMBOL_CLASS);
} else { } else {
name = zend_generate_anon_class_name(decl->lex_pos); name = zend_generate_anon_class_name(decl->start_lineno);
lcname = zend_string_tolower(name); lcname = zend_string_tolower(name);
} }
lcname = zend_new_interned_string(lcname); lcname = zend_new_interned_string(lcname);
@ -6728,20 +6721,19 @@ zend_op *zend_compile_class_decl(zend_ast *ast, zend_bool toplevel) /* {{{ */
opline->extended_value = zend_alloc_cache_slot(); opline->extended_value = zend_alloc_cache_slot();
opline->result_type = IS_VAR; opline->result_type = IS_VAR;
opline->result.var = get_temporary_variable(); opline->result.var = get_temporary_variable();
if (!zend_hash_add_ptr(CG(class_table), lcname, ce)) { if (!zend_hash_add_ptr(CG(class_table), lcname, ce)) {
/* this anonymous class has been included */ zend_error_noreturn(E_ERROR,
zval zv; "Runtime definition key collision for %s. This is a bug", ZSTR_VAL(name));
ZVAL_PTR(&zv, ce);
destroy_zend_class(&zv);
return opline;
} }
} else { } else {
zend_string *key = zend_build_runtime_definition_key(lcname, decl->lex_pos); zend_string *key = zend_build_runtime_definition_key(lcname, decl->start_lineno);
/* RTD key is placed after lcname literal in op1 */ /* RTD key is placed after lcname literal in op1 */
zend_add_literal_string(&key); zend_add_literal_string(&key);
zend_hash_update_ptr(CG(class_table), key, ce); if (!zend_hash_add_ptr(CG(class_table), key, ce)) {
zend_error_noreturn(E_ERROR,
"Runtime definition key collision for class %s. This is a bug", ZSTR_VAL(name));
}
opline->opcode = ZEND_DECLARE_CLASS; opline->opcode = ZEND_DECLARE_CLASS;
if (extends_ast && toplevel if (extends_ast && toplevel

View file

@ -127,6 +127,8 @@ struct _zend_compiler_globals {
HashTable *delayed_variance_obligations; HashTable *delayed_variance_obligations;
HashTable *delayed_autoloads; HashTable *delayed_autoloads;
uint32_t rtd_key_counter;
}; };

View file

@ -439,8 +439,16 @@ static void zend_accel_function_hash_copy(HashTable *target, HashTable *source)
t = zend_hash_find_ex(target, p->key, 1); t = zend_hash_find_ex(target, p->key, 1);
if (UNEXPECTED(t != NULL)) { if (UNEXPECTED(t != NULL)) {
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) { if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
/* Mangled key */ /* Runtime definition key. There are two circumstances under which the key can
t = zend_hash_update(target, p->key, &p->val); * already be defined:
* 1. The file has been re-included without being changed in the meantime. In
* this case we can keep the old value, because we know that the definition
* hasn't changed.
* 2. The file has been changed in the meantime, but the RTD key ends up colliding.
* This would be a bug.
* As we can't distinguish these cases, we assume that it is 1. and keep the old
* value. */
continue;
} else { } else {
goto failure; goto failure;
} }
@ -483,8 +491,8 @@ static void zend_accel_function_hash_copy_from_shm(HashTable *target, HashTable
t = zend_hash_find_ex(target, p->key, 1); t = zend_hash_find_ex(target, p->key, 1);
if (UNEXPECTED(t != NULL)) { if (UNEXPECTED(t != NULL)) {
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) { if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
/* Mangled key */ /* See comment in zend_accel_function_hash_copy(). */
zend_hash_update_ptr(target, p->key, Z_PTR(p->val)); continue;
} else { } else {
goto failure; goto failure;
} }
@ -526,7 +534,7 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source)
t = zend_hash_find_ex(target, p->key, 1); t = zend_hash_find_ex(target, p->key, 1);
if (UNEXPECTED(t != NULL)) { if (UNEXPECTED(t != NULL)) {
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) { if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
/* Mangled key - ignore and wait for runtime */ /* See comment in zend_accel_function_hash_copy(). */
continue; continue;
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) { } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
zend_class_entry *ce1 = Z_PTR(p->val); 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
t = zend_hash_find_ex(target, p->key, 1); t = zend_hash_find_ex(target, p->key, 1);
if (UNEXPECTED(t != NULL)) { if (UNEXPECTED(t != NULL)) {
if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) { if (EXPECTED(ZSTR_LEN(p->key) > 0) && EXPECTED(ZSTR_VAL(p->key)[0] == 0)) {
/* Mangled key - ignore and wait for runtime */ /* See comment in zend_accel_function_hash_copy(). */
continue; continue;
} else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) { } else if (UNEXPECTED(!ZCG(accel_directives).ignore_dups)) {
zend_class_entry *ce1 = Z_PTR(p->val); zend_class_entry *ce1 = Z_PTR(p->val);