Skip to content

Fetch for read in nested property assignments #12244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Zend/Optimizer/zend_dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -609,12 +609,14 @@ ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block
fprintf(stderr, " (ref)");
}
}
if ((ZEND_VM_EXT_DIM_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) {
if ((ZEND_VM_EXT_DIM_WRITE|ZEND_VM_EXT_OBJ_W_CONTAINER|ZEND_VM_EXT_FETCH_REF) & flags) {
uint32_t obj_flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
if (obj_flags == ZEND_FETCH_REF) {
fprintf(stderr, " (ref)");
} else if (obj_flags == ZEND_FETCH_DIM_WRITE) {
fprintf(stderr, " (dim write)");
} else if (obj_flags == ZEND_FETCH_OBJ_W_CONTAINER) {
fprintf(stderr, " (obj container)");
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion Zend/tests/031.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ test($arr[]);

?>
--EXPECTF--
Fatal error: Cannot use [] for reading in %s on line %d
Fatal error: Uncaught Error: Cannot use [] for reading in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
14 changes: 13 additions & 1 deletion Zend/tests/033.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,17 @@ Warning: Trying to access array offset on null in %s on line %d
Warning: Trying to access array offset on null in %s on line %d

Warning: Attempt to read property "foo" on null in %s on line %d

Warning: Undefined variable $arr in %s on line %d

Warning: Trying to access array offset on null in %s on line %d

Warning: Trying to access array offset on null in %s on line %d

Warning: Trying to access array offset on null in %s on line %d

Warning: Trying to access array offset on null in %s on line %d

Warning: Trying to access array offset on null in %s on line %d
Attempt to assign property "foo" on null
Attempt to assign property "bar" on null
Cannot use [] for reading
5 changes: 4 additions & 1 deletion Zend/tests/bug41351.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ foreach($a[] as $b) {
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot use [] for reading in %s on line %d
Fatal error: Uncaught Error: Cannot use [] for reading in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
5 changes: 4 additions & 1 deletion Zend/tests/bug41351_2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ foreach($a[]['test'] as $b) {
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot use [] for reading in %s on line %d
Fatal error: Uncaught Error: Cannot use [] for reading in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
7 changes: 6 additions & 1 deletion Zend/tests/bug41351_3.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ foreach($a['test'][] as $b) {
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot use [] for reading in %s on line %d
Warning: Undefined array key "test" in %s on line %d

Fatal error: Uncaught Error: Cannot use [] for reading in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
15 changes: 15 additions & 0 deletions Zend/tests/bug41813.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Bug #41813 (segmentation fault when using string offset as an object)
--FILE--
<?php

$foo = "50";
$foo[0]->bar = "xyz";

echo "Done\n";
?>
--EXPECTF--
Fatal error: Uncaught Error: Attempt to assign property "bar" on string in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
16 changes: 16 additions & 0 deletions Zend/tests/bug41919.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Bug #41919 (crash in string to array conversion)
--FILE--
<?php
$foo="50";
$foo[3]->bar[1] = "bang";

echo "ok\n";
?>
--EXPECTF--
Warning: Uninitialized string offset 3 in %s on line %d

Fatal error: Uncaught Error: Attempt to modify property "bar" on string in %s:%d
Stack trace:
#0 {main}
thrown in %sbug41919.php on line %d
12 changes: 12 additions & 0 deletions Zend/tests/bug47704.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--TEST--
Bug #47704 (crashes on some "bad" operations with string offsets)
--FILE--
<?php
$s = "abd";
$s[0]->a += 1;
?>
--EXPECTF--
Fatal error: Uncaught Error: Attempt to assign property "a" on string in %s:%d
Stack trace:
#0 {main}
thrown in %sbug47704.php on line %d
12 changes: 9 additions & 3 deletions Zend/tests/bug52041.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,25 @@ Warning: Undefined variable $x in %s on line %d
Attempt to assign property "a" on null

Warning: Undefined variable $x in %s on line %d
Attempt to modify property "a" on null

Warning: Attempt to read property "a" on null in %s on line %d
Attempt to assign property "b" on null

Warning: Undefined variable $x in %s on line %d
Attempt to increment/decrement property "a" on null

Warning: Undefined variable $x in %s on line %d
Attempt to modify property "a" on null

Warning: Attempt to read property "a" on null in %s on line %d
Attempt to increment/decrement property "b" on null

Warning: Undefined variable $x in %s on line %d
Attempt to assign property "a" on null

Warning: Undefined variable $x in %s on line %d
Attempt to modify property "a" on null

Warning: Attempt to read property "a" on null in %s on line %d
Attempt to assign property "b" on null

Warning: Undefined variable $x in %s on line %d

Expand Down
4 changes: 2 additions & 2 deletions Zend/tests/bug55007.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Bug #55007 (compiler fail after previous fail)
<?php

spl_autoload_register(function ($classname) {
if ('CompileErrorClass'==$classname) eval('class CompileErrorClass { function foo() { $a[]; } }');
if ('CompileErrorClass'==$classname) eval('class int {}');
if ('MyErrorHandler'==$classname) eval('class MyErrorHandler { function __construct() { print "My error handler runs.\n"; } }');
});

Expand All @@ -19,5 +19,5 @@ new CompileErrorClass();

?>
--EXPECTF--
Fatal error: Cannot use [] for reading in %s(%d) : eval()'d code on line %d
Fatal error: Cannot use 'int' as class name as it is reserved in %s on line %d
My error handler runs.
20 changes: 17 additions & 3 deletions Zend/tests/bug75921.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,29 @@ Attempt to modify property "a" on null

Warning: Undefined variable $null in %s on line %d
NULL
Attempt to modify property "a" on null

Warning: Undefined variable $null in %s on line %d

Warning: Attempt to read property "a" on null in %s on line %d
Attempt to assign property "b" on null

Warning: Undefined variable $null in %s on line %d
NULL
Attempt to modify property "a" on null

Warning: Undefined variable $null in %s on line %d

Warning: Attempt to read property "a" on null in %s on line %d

Warning: Trying to access array offset on null in %s on line %d
Attempt to assign property "b" on null

Warning: Undefined variable $null in %s on line %d
NULL
Attempt to modify property "a" on null

Warning: Undefined variable $null in %s on line %d

Warning: Attempt to read property "a" on null in %s on line %d
Attempt to modify property "b" on null

Warning: Undefined variable $null in %s on line %d
NULL
4 changes: 3 additions & 1 deletion Zend/tests/bug78531.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ Warning: Undefined variable $u3 in %s on line %d
Attempt to increment/decrement property "a" on null

Warning: Undefined variable $u4 in %s on line %d
Attempt to modify property "a" on null

Warning: Attempt to read property "a" on null in %s on line %d
Attempt to assign property "a" on null
5 changes: 4 additions & 1 deletion Zend/tests/errmsg_006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ $b = $a[];
echo "Done\n";
?>
--EXPECTF--
Fatal error: Cannot use [] for reading in %s on line %d
Fatal error: Uncaught Error: Cannot use [] for reading in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
13 changes: 13 additions & 0 deletions Zend/tests/new_offset_assign_obj.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
Assigning to a property of a new offset
--FILE--
<?php

$arr[][]->bar = 2;

?>
--EXPECTF--
Fatal error: Uncaught Error: Cannot use [] for reading in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
4 changes: 2 additions & 2 deletions Zend/tests/readonly_props/variation_nested.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ Init: 1, op: im: done
Init: 1, op: is: 1
Init: 1, op: us: done
Init: 0, op: r: Typed property Test::$prop must not be accessed before initialization
Init: 0, op: w: Cannot indirectly modify readonly property Test::$prop
Init: 0, op: w: Typed property Test::$prop must not be accessed before initialization
Init: 0, op: rw: Typed property Test::$prop must not be accessed before initialization
Init: 0, op: im: Cannot indirectly modify readonly property Test::$prop
Init: 0, op: im: Typed property Test::$prop must not be accessed before initialization
Init: 0, op: is: 0
Init: 0, op: us: done
16 changes: 8 additions & 8 deletions Zend/tests/string_offset_as_object.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ try {

?>
--EXPECT--
Cannot use string offset as an object
Cannot use string offset as an object
Cannot use string offset as an object
Cannot use string offset as an object
Cannot use string offset as an object
Cannot use string offset as an object
Cannot use string offset as an object
Cannot use string offset as an object
Attempt to assign property "bar" on string
Attempt to modify property "bar" on string
Attempt to assign property "bar" on string
Attempt to modify property "bar" on string
Attempt to increment/decrement property "bar" on string
Attempt to increment/decrement property "bar" on string
Attempt to increment/decrement property "bar" on string
Attempt to increment/decrement property "bar" on string
Cannot use string offset as an object
38 changes: 36 additions & 2 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -3022,7 +3022,8 @@ static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t
zend_separate_if_call_and_write(&var_node, var_ast, type);

if (dim_ast == NULL) {
if (type == BP_VAR_R || type == BP_VAR_IS) {
/* Allow BP_VAR_R to support auto-vivification in custom object handlers. */
if (type == BP_VAR_IS) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use [] for reading");
}
if (type == BP_VAR_UNSET) {
Expand Down Expand Up @@ -3053,6 +3054,29 @@ static zend_op *zend_compile_dim(znode *result, zend_ast *ast, uint32_t type, bo
}
/* }}} */

/* Linear backwards search for OBJ_R/DIM_R fetches, adding the ZEND_FETCH_OBJ_W_CONTAINER flag to them. */
static void mark_as_obj_w_contaner(zend_op *op)
{
zend_op *start_op = zend_stack_base(&CG(delayed_oplines_stack));

while (true) {
if ((op->opcode != ZEND_FETCH_OBJ_R && op->opcode != ZEND_FETCH_DIM_R)) {
break;
}
op->extended_value |= ZEND_FETCH_OBJ_W_CONTAINER;
if (!(op->op1_type & (IS_VAR|IS_TMP_VAR))) {
break;
}
uint32_t var = op->op1.var;
op--;
if (op < start_op
|| !(op->result_type & (IS_VAR|IS_TMP_VAR))
|| op->result.var != var) {
break;
}
}
}

static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t type) /* {{{ */
{
zend_ast *obj_ast = ast->child[0];
Expand All @@ -3074,7 +3098,17 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t
* check for a nullsafe access. */
} else {
zend_short_circuiting_mark_inner(obj_ast);
opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0);
int fetch_mode = type;
/* In $a->b->c = $d, fetch $a->b for read and only ->c for write.
* We will never modify $a->b itself, only the object it holds. */
bool change_fetch_mode = (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_FUNC_ARG);
if (change_fetch_mode) {
fetch_mode = BP_VAR_R;
}
opline = zend_delayed_compile_var(&obj_node, obj_ast, fetch_mode, 0);
if (opline && change_fetch_mode) {
mark_as_obj_w_contaner(opline);
}
if (opline && (opline->opcode == ZEND_FETCH_DIM_W
|| opline->opcode == ZEND_FETCH_DIM_RW
|| opline->opcode == ZEND_FETCH_DIM_FUNC_ARG
Expand Down
1 change: 1 addition & 0 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
/* Only one of these can ever be in use */
#define ZEND_FETCH_REF 1
#define ZEND_FETCH_DIM_WRITE 2
#define ZEND_FETCH_OBJ_W_CONTAINER 3
#define ZEND_FETCH_OBJ_FLAGS 3

/* Used to mark what kind of operation a writing FETCH_DIM is used in,
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -2749,7 +2749,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
zend_long offset;

try_string_offset:
if (UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
if (dim_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(dim) != IS_LONG)) {
switch (Z_TYPE_P(dim)) {
case IS_STRING:
{
Expand Down Expand Up @@ -2837,7 +2837,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
zend_object *obj = Z_OBJ_P(container);

GC_ADDREF(obj);
if (ZEND_CONST_COND(dim_type == IS_CV, 1) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
if (dim_type == IS_CV && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
dim = ZVAL_UNDEFINED_OP2();
}
if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
Expand Down
Loading