diff --git a/Zend/tests/gh10497.phpt b/Zend/tests/gh10497.phpt new file mode 100644 index 0000000000000..3ac7ad027af23 --- /dev/null +++ b/Zend/tests/gh10497.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-10497: Allow direct modification of object stored in a constant +--FILE-- +b = 42; +var_dump(a->b); + +const obj = new stdClass; +obj->foo = 'bar'; +obj->baz = 123; +var_dump(obj->foo, obj->baz); + +const nested = new stdClass; +nested->inner = new stdClass; +nested->inner->value = 999; +var_dump(nested->inner->value); + +const readTest = new stdClass; +readTest->prop = 'test'; +echo readTest->prop . "\n"; + +var_dump(isset(readTest->prop)); +var_dump(empty(readTest->missing)); + +const modTest = new stdClass; +modTest->val = 1; +modTest->val = 2; +var_dump(modTest->val); +?> +--EXPECT-- +int(42) +string(3) "bar" +int(123) +int(999) +test +bool(true) +bool(true) +int(2) diff --git a/Zend/tests/gh12102_3.phpt b/Zend/tests/gh12102_3.phpt index 741bce5ab1ba1..c460fe7428a18 100644 --- a/Zend/tests/gh12102_3.phpt +++ b/Zend/tests/gh12102_3.phpt @@ -5,11 +5,8 @@ GH-12102: Incorrect "Cannot use temporary expression in write context" error for function test() { byVal(C[0]); - try { - byRef(C[0]); - } catch (Error $e) { - echo $e->getMessage(), "\n"; - } + byRef(C[0]); + var_dump(C); } /* Intentionally declared after test() to avoid compile-time checking of ref args. */ @@ -21,6 +18,7 @@ function byVal($arg) { } function byRef(&$arg) { + $arg = 'modified'; var_dump($arg); } @@ -29,4 +27,8 @@ test('y'); ?> --EXPECT-- string(3) "foo" -Cannot use temporary expression in write context +string(8) "modified" +array(1) { + [0]=> + string(3) "foo" +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 5eba2ec1366fa..47eab5765b29a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -11101,7 +11101,7 @@ static void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */ } /* }}} */ -static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */ +static zend_op *zend_compile_const_inner(znode *result, const zend_ast *ast, bool use_tmp) /* {{{ */ { zend_ast *name_ast = ast->child[0]; @@ -11125,17 +11125,21 @@ static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */ result->op_type = IS_CONST; ZVAL_LONG(&result->u.constant, Z_LVAL_P(zend_ast_get_zval(last->child[0]))); zend_string_release_ex(resolved_name, 0); - return; + return NULL; } } if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified)) { result->op_type = IS_CONST; zend_string_release_ex(resolved_name, 0); - return; + return NULL; } - opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL); + if (use_tmp) { + opline = zend_emit_op_tmp(result, ZEND_FETCH_CONSTANT, NULL, NULL); + } else { + opline = zend_emit_op(result, ZEND_FETCH_CONSTANT, NULL, NULL); + } opline->op2_type = IS_CONST; if (is_fully_qualified || !FC(current_namespace)) { @@ -11148,6 +11152,13 @@ static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */ resolved_name, true); } opline->extended_value = zend_alloc_cache_slot(); + return opline; +} +/* }}} */ + +static void zend_compile_const(znode *result, const zend_ast *ast) /* {{{ */ +{ + zend_compile_const_inner(result, ast, true); } /* }}} */ @@ -12085,6 +12096,8 @@ static zend_op *zend_compile_var_inner(znode *result, zend_ast *ast, uint32_t ty case ZEND_AST_ZNODE: *result = *zend_ast_get_znode(ast); return NULL; + case ZEND_AST_CONST: + return zend_compile_const_inner(result, ast, false); default: if (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) { zend_error_noreturn(E_COMPILE_ERROR,