Skip to content

Commit

Permalink
Fix append binary op
Browse files Browse the repository at this point in the history
  • Loading branch information
Girgias committed Jun 10, 2024
1 parent 46be651 commit fdada4a
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 7 deletions.
6 changes: 2 additions & 4 deletions Zend/tests/bug69955.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,9 @@ $c10 = new C10;

var_dump($c10[] += 5);
?>
--EXPECT--
--EXPECTF--
Inside C10::offsetGet
NULL

Inside C10::offsetSet
NULL
int(105)
Notice: Indirect modification of overloaded element of C10 has no effect in %s on line %d
int(105)
75 changes: 75 additions & 0 deletions Zend/tests/offsets/appending_fetch_RW_containers.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
--TEST--
Appending containers via a binary RW op $c[] .= $v;
--FILE--
<?php

require_once __DIR__ . DIRECTORY_SEPARATOR . 'test_offset_helpers.inc';

foreach ($containers as $container) {
echo zend_test_var_export($container), " container:\n";
try {
$container[] .= 'value';
var_dump($container);
} catch (\Throwable $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
}

?>
--EXPECTF--
NULL container:
array(1) {
[0]=>
string(5) "value"
}
false container:

Deprecated: Automatic conversion of false to array is deprecated in %s on line %d
array(1) {
[0]=>
string(5) "value"
}
true container:
Error: Cannot use a scalar value as an array
4 container:
Error: Cannot use a scalar value as an array
5.5 container:
Error: Cannot use a scalar value as an array
'10' container:
Error: [] operator not supported for strings
'25.5' container:
Error: [] operator not supported for strings
'string' container:
Error: [] operator not supported for strings
[] container:
array(1) {
[0]=>
string(5) "value"
}
STDERR container:
Error: Cannot use a scalar value as an array
new stdClass() container:
Error: Cannot use object of type stdClass as array
new ArrayObject() container:
object(ArrayObject)#2 (1) {
["storage":"ArrayObject":private]=>
array(1) {
[0]=>
string(5) "value"
}
}
new A() container:
string(12) "A::offsetGet"
NULL

Notice: Indirect modification of overloaded element of A has no effect in %s on line %d
object(A)#3 (0) {
}
new B() container:
object(B)#4 (1) {
["storage":"ArrayObject":private]=>
array(1) {
[0]=>
string(5) "value"
}
}
52 changes: 49 additions & 3 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1657,14 +1657,57 @@ static zend_always_inline int zend_binary_op(zval *ret, zval *op1, zval *op2 OPL
return zend_binary_ops[opcode - ZEND_ADD](ret, op1, op2);
}

static zend_never_inline void zend_fetch_object_dimension_address(zval *result, zend_object *obj, zval *offset, int offset_type, int type EXECUTE_DATA_DC);
static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *ref, zval *value OPLINE_DC EXECUTE_DATA_DC);

static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zval *dim OPLINE_DC EXECUTE_DATA_DC)
{
zval *value;
zval *z;
zval rv, res;

ZEND_ASSERT(dim && "Offset is NULL for Read-Write operation");
GC_ADDREF(obj);
if (UNEXPECTED(dim == NULL)) {
value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1);
if (EXPECTED(obj->ce->dimension_handlers)) {
if (obj->ce->dimension_handlers->fetch_append) {
ZEND_ASSERT(zend_check_dimension_interfaces_implemented(obj, /* has_offset */ false, BP_VAR_FETCH));

zval zref;
zend_fetch_object_dimension_address(&zref, obj, NULL, 0, BP_VAR_W EXECUTE_DATA_DC);

ZEND_ASSERT(Z_TYPE(zref) != IS_INDIRECT && "No support for indirect vars yet");
ZEND_ASSERT(Z_ISREF(zref));

zend_reference *ref = Z_REF(zref);
zval *var_ptr = Z_REFVAL(zref);
if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
zend_binary_assign_op_typed_ref(ref, value OPLINE_CC EXECUTE_DATA_CC);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
goto clean_up;
}
zend_binary_op(var_ptr, var_ptr, value OPLINE_CC);

if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_COPY(EX_VAR(opline->result.var), var_ptr);
}
zval_ptr_dtor(&zref);
} else {
zend_invalid_use_of_object_as_array(obj, /* has_offset */ false, BP_VAR_FETCH);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
}
} else {
zend_use_object_as_array(obj);
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
ZVAL_NULL(EX_VAR(opline->result.var));
}
}
goto clean_up;
}

ZEND_ASSERT(dim && "Offset is NULL for Read-Write operation");
if (UNEXPECTED(Z_ISUNDEF_P(dim))) {
dim = ZVAL_UNDEFINED_OP2();
}
Expand All @@ -1677,6 +1720,9 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv
ZEND_ASSERT(zend_check_dimension_interfaces_implemented(obj, /* has_offset */ true, BP_VAR_RW));

ZVAL_DEREF(dim);
zval *z;
zval rv, res;

z = obj->ce->dimension_handlers->read_dimension(obj, dim, &rv);
if (UNEXPECTED(z == NULL)) {
ZEND_ASSERT(EG(exception) && "returned NULL without exception");
Expand Down

0 comments on commit fdada4a

Please sign in to comment.