Allow arbitrary expressions in static variable initializer

Closes GH-9301
This commit is contained in:
Ilija Tovilo 2022-08-11 17:42:54 +02:00
parent 3189a9f94a
commit 0b1d750d91
No known key found for this signature in database
GPG key ID: A4F5D403F118200A
44 changed files with 1118 additions and 690 deletions

View file

@ -2293,6 +2293,7 @@ static inline void zend_update_jump_target(uint32_t opnum_jump, uint32_t opnum_t
case ZEND_JMP_SET:
case ZEND_COALESCE:
case ZEND_JMP_NULL:
case ZEND_BIND_INIT_STATIC_OR_JMP:
opline->op2.opline_num = opnum_target;
break;
EMPTY_SWITCH_DEFAULT_CASE()
@ -4885,16 +4886,55 @@ static void zend_compile_static_var_common(zend_string *var_name, zval *value, u
static void zend_compile_static_var(zend_ast *ast) /* {{{ */
{
zend_ast *var_ast = ast->child[0];
zend_ast **value_ast_ptr = &ast->child[1];
zval value_zv;
zend_string *var_name = zend_ast_get_str(var_ast);
if (*value_ast_ptr) {
zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ true);
} else {
ZVAL_NULL(&value_zv);
if (zend_string_equals_literal(var_name, "this")) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use $this as static variable");
}
zend_compile_static_var_common(zend_ast_get_str(var_ast), &value_zv, ZEND_BIND_REF);
if (!CG(active_op_array)->static_variables) {
if (CG(active_op_array)->scope) {
CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
}
CG(active_op_array)->static_variables = zend_new_array(8);
}
if (zend_hash_exists(CG(active_op_array)->static_variables, var_name)) {
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate declaration of static variable $%s", ZSTR_VAL(var_name));
}
zend_eval_const_expr(&ast->child[1]);
zend_ast *value_ast = ast->child[1];
if (!value_ast || value_ast->kind == ZEND_AST_ZVAL) {
zval *value_zv = value_ast
? zend_ast_get_zval(value_ast)
: &EG(uninitialized_zval);
Z_TRY_ADDREF_P(value_zv);
zend_compile_static_var_common(var_name, value_zv, ZEND_BIND_REF);
} else {
zend_op *opline;
zval *placeholder_ptr = zend_hash_update(CG(active_op_array)->static_variables, var_name, &EG(uninitialized_zval));
Z_TYPE_EXTRA_P(placeholder_ptr) |= IS_STATIC_VAR_UNINITIALIZED;
uint32_t placeholder_offset = (uint32_t)((char*)placeholder_ptr - (char*)CG(active_op_array)->static_variables->arData);
uint32_t static_def_jmp_opnum = get_next_op_number();
opline = zend_emit_op(NULL, ZEND_BIND_INIT_STATIC_OR_JMP, NULL, NULL);
opline->op1_type = IS_CV;
opline->op1.var = lookup_cv(var_name);
opline->extended_value = placeholder_offset;
znode expr;
zend_compile_expr(&expr, value_ast);
opline = zend_emit_op(NULL, ZEND_BIND_STATIC, NULL, &expr);
opline->op1_type = IS_CV;
opline->op1.var = lookup_cv(var_name);
opline->extended_value = placeholder_offset | ZEND_BIND_REF;
zend_update_jump_target_to_next(static_def_jmp_opnum);
}
}
/* }}} */