mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: Fix array clobering by user error handler
This commit is contained in:
commit
76075823e7
@ -2,7 +2,17 @@
|
||||
Array object clobbering by user error handler
|
||||
--FILE--
|
||||
<?php
|
||||
class A {
|
||||
class A implements ArrayAccess {
|
||||
public function &offsetGet($n): mixed {
|
||||
return null;
|
||||
}
|
||||
public function offsetSet($n, $v): void {
|
||||
}
|
||||
public function offsetUnset($n): void {
|
||||
}
|
||||
public function offsetExists($n): bool {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
set_error_handler(function () {
|
||||
|
27
Zend/tests/objects_035.phpt
Normal file
27
Zend/tests/objects_035.phpt
Normal file
@ -0,0 +1,27 @@
|
||||
--TEST--
|
||||
Array object clobbering by user error handler
|
||||
--FILE--
|
||||
<?php
|
||||
class A implements ArrayAccess {
|
||||
public function &offsetGet($n): mixed {
|
||||
return null;
|
||||
}
|
||||
public function offsetSet($n, $v): void {
|
||||
}
|
||||
public function offsetUnset($n): void {
|
||||
}
|
||||
public function offsetExists($n): bool {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
set_error_handler(function () {
|
||||
$GLOBALS['a'] = null;
|
||||
});
|
||||
|
||||
$a = new A;
|
||||
$a[$c];
|
||||
?>
|
||||
DONE
|
||||
--EXPECT--
|
||||
DONE
|
@ -1394,9 +1394,9 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_string_offset
|
||||
zend_type_error("Cannot access offset of type %s on string", zend_zval_type_name(offset));
|
||||
}
|
||||
|
||||
static zend_never_inline void zend_assign_to_object_dim(zval *object, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC)
|
||||
static zend_never_inline void zend_assign_to_object_dim(zend_object *obj, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC)
|
||||
{
|
||||
Z_OBJ_HT_P(object)->write_dimension(Z_OBJ_P(object), dim, value);
|
||||
obj->handlers->write_dimension(obj, dim, value);
|
||||
|
||||
if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
|
||||
ZVAL_COPY(EX_VAR(opline->result.var), value);
|
||||
@ -1431,6 +1431,7 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv
|
||||
zval *z;
|
||||
zval rv, res;
|
||||
|
||||
GC_ADDREF(obj);
|
||||
value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1);
|
||||
if ((z = obj->handlers->read_dimension(obj, property, BP_VAR_R, &rv)) != NULL) {
|
||||
|
||||
@ -1451,6 +1452,9 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv
|
||||
}
|
||||
}
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *ref, zval *value OPLINE_DC EXECUTE_DATA_DC)
|
||||
@ -2464,22 +2468,17 @@ fetch_from_array:
|
||||
}
|
||||
ZVAL_UNDEF(result);
|
||||
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
zend_object *obj = Z_OBJ_P(container);
|
||||
GC_ADDREF(obj);
|
||||
if (ZEND_CONST_COND(dim_type == IS_CV, dim != NULL) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
|
||||
zend_object *obj = Z_OBJ_P(container);
|
||||
GC_ADDREF(obj);
|
||||
dim = ZVAL_UNDEFINED_OP2();
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
ZVAL_NULL(result);
|
||||
return;
|
||||
}
|
||||
} else if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
|
||||
dim++;
|
||||
}
|
||||
retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, type, result);
|
||||
retval = obj->handlers->read_dimension(obj, dim, type, result);
|
||||
|
||||
if (UNEXPECTED(retval == &EG(uninitialized_zval))) {
|
||||
zend_class_entry *ce = Z_OBJCE_P(container);
|
||||
zend_class_entry *ce = obj->ce;
|
||||
|
||||
ZVAL_NULL(result);
|
||||
zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
|
||||
@ -2490,7 +2489,7 @@ fetch_from_array:
|
||||
retval = result;
|
||||
}
|
||||
if (Z_TYPE_P(retval) != IS_OBJECT) {
|
||||
zend_class_entry *ce = Z_OBJCE_P(container);
|
||||
zend_class_entry *ce = obj->ce;
|
||||
zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name));
|
||||
}
|
||||
} else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) {
|
||||
@ -2503,6 +2502,9 @@ fetch_from_array:
|
||||
ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
|
||||
ZVAL_UNDEF(result);
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
} else {
|
||||
if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) {
|
||||
if (type != BP_VAR_W && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
|
||||
@ -2670,13 +2672,16 @@ try_string_offset:
|
||||
ZVAL_CHAR(result, c);
|
||||
}
|
||||
} else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) {
|
||||
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)) {
|
||||
dim = ZVAL_UNDEFINED_OP2();
|
||||
}
|
||||
if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
|
||||
dim++;
|
||||
}
|
||||
retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, type, result);
|
||||
retval = obj->handlers->read_dimension(obj, dim, type, result);
|
||||
|
||||
ZEND_ASSERT(result != NULL);
|
||||
if (retval) {
|
||||
@ -2688,6 +2693,9 @@ try_string_offset:
|
||||
} else {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
} else {
|
||||
if (type != BP_VAR_IS && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) {
|
||||
container = ZVAL_UNDEFINED_OP1();
|
||||
|
@ -2612,35 +2612,29 @@ ZEND_VM_C_LABEL(try_assign_dim_array):
|
||||
}
|
||||
}
|
||||
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
|
||||
zend_object *obj = Z_OBJ_P(object_ptr);
|
||||
|
||||
GC_ADDREF(obj);
|
||||
dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
if (OP2_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) {
|
||||
zend_object *obj = Z_OBJ_P(object_ptr);
|
||||
GC_ADDREF(obj);
|
||||
dim = ZVAL_UNDEFINED_OP2();
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
ZEND_VM_C_GOTO(assign_dim_error);
|
||||
}
|
||||
} else if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) {
|
||||
dim++;
|
||||
}
|
||||
|
||||
value = GET_OP_DATA_ZVAL_PTR_UNDEF(BP_VAR_R);
|
||||
if (OP_DATA_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) {
|
||||
zend_object *obj = Z_OBJ_P(object_ptr);
|
||||
GC_ADDREF(obj);
|
||||
value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC);
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
ZEND_VM_C_GOTO(assign_dim_error);
|
||||
}
|
||||
} else if (OP_DATA_TYPE & (IS_CV|IS_VAR)) {
|
||||
ZVAL_DEREF(value);
|
||||
}
|
||||
|
||||
zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC);
|
||||
zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC);
|
||||
|
||||
FREE_OP_DATA();
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
} else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
|
||||
if (OP2_TYPE == IS_UNUSED) {
|
||||
zend_use_new_element_for_string();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -904,13 +904,15 @@ try_string_offset:
|
||||
static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval *dim, zval *result)
|
||||
{
|
||||
zval *retval;
|
||||
zend_object *obj = Z_OBJ_P(container);
|
||||
|
||||
GC_ADDREF(obj);
|
||||
if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
|
||||
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
|
||||
dim = &EG(uninitialized_zval);
|
||||
}
|
||||
|
||||
retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, BP_VAR_R, result);
|
||||
retval = obj->handlers->read_dimension(obj, dim, BP_VAR_R, result);
|
||||
|
||||
if (retval) {
|
||||
if (result != retval) {
|
||||
@ -921,18 +923,23 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval
|
||||
} else {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval *dim, zval *result)
|
||||
{
|
||||
zval *retval;
|
||||
zend_object *obj = Z_OBJ_P(container);
|
||||
|
||||
GC_ADDREF(obj);
|
||||
if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
|
||||
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
|
||||
dim = &EG(uninitialized_zval);
|
||||
}
|
||||
|
||||
retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, BP_VAR_IS, result);
|
||||
retval = obj->handlers->read_dimension(obj, dim, BP_VAR_IS, result);
|
||||
|
||||
if (retval) {
|
||||
if (result != retval) {
|
||||
@ -943,6 +950,9 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval
|
||||
} else {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_never_inline void zend_assign_to_string_offset(zval *str, zval *dim, zval *value, zval *result)
|
||||
@ -1103,16 +1113,11 @@ static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval
|
||||
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
|
||||
zend_object *obj = Z_OBJ_P(object_ptr);
|
||||
|
||||
GC_ADDREF(obj);
|
||||
if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) {
|
||||
const zend_op *opline = EG(current_execute_data)->opline;
|
||||
GC_ADDREF(obj);
|
||||
zend_jit_undefined_op_helper(opline->op2.var);
|
||||
dim = &EG(uninitialized_zval);
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
ZVAL_NULL(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
retval = obj->handlers->read_dimension(obj, dim, type, result);
|
||||
@ -1141,6 +1146,9 @@ static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval
|
||||
ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception");
|
||||
ZVAL_UNDEF(result);
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
} else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) {
|
||||
if (!dim) {
|
||||
zend_throw_error(NULL, "[] operator not supported for strings");
|
||||
@ -1208,38 +1216,23 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim
|
||||
if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) {
|
||||
zend_object *obj = Z_OBJ_P(object_ptr);
|
||||
|
||||
GC_ADDREF(obj);
|
||||
if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) {
|
||||
const zend_op *opline = EG(current_execute_data)->opline;
|
||||
GC_ADDREF(obj);
|
||||
zend_jit_undefined_op_helper(opline->op2.var);
|
||||
dim = &EG(uninitialized_zval);
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
if (result) {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) {
|
||||
const zend_op *op_data = EG(current_execute_data)->opline + 1;
|
||||
ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV);
|
||||
GC_ADDREF(obj);
|
||||
zend_jit_undefined_op_helper(op_data->op1.var);
|
||||
value = &EG(uninitialized_zval);
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
if (result) {
|
||||
ZVAL_NULL(result);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ZVAL_DEREF(value);
|
||||
}
|
||||
|
||||
Z_OBJ_HT_P(object_ptr)->write_dimension(obj, dim, value);
|
||||
obj->handlers->write_dimension(obj, dim, value);
|
||||
if (result) {
|
||||
if (EXPECTED(!EG(exception))) {
|
||||
ZVAL_COPY(result, value);
|
||||
@ -1247,6 +1240,9 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim
|
||||
ZVAL_UNDEF(result);
|
||||
}
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
}
|
||||
return;
|
||||
} else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && EXPECTED(dim != NULL)) {
|
||||
zend_assign_to_string_offset(object_ptr, dim, value, result);
|
||||
@ -1311,18 +1307,11 @@ static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *d
|
||||
zval *z;
|
||||
zval rv, res;
|
||||
|
||||
GC_ADDREF(obj);
|
||||
if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) {
|
||||
const zend_op *opline = EG(current_execute_data)->opline;
|
||||
GC_ADDREF(obj);
|
||||
zend_jit_undefined_op_helper(opline->op2.var);
|
||||
dim = &EG(uninitialized_zval);
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
//??? if (retval) {
|
||||
//??? ZVAL_NULL(retval);
|
||||
//??? }
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
z = obj->handlers->read_dimension(obj, dim, BP_VAR_R, &rv);
|
||||
@ -1338,6 +1327,12 @@ static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *d
|
||||
} else {
|
||||
zend_error(E_WARNING, "Attempt to assign property of non-object");
|
||||
}
|
||||
if (UNEXPECTED(GC_DELREF(obj) == 0)) {
|
||||
zend_objects_store_del(obj);
|
||||
//??? if (retval) {
|
||||
//??? ZVAL_NULL(retval);
|
||||
//??? }
|
||||
}
|
||||
} else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) {
|
||||
if (!dim) {
|
||||
zend_throw_error(NULL, "[] operator not supported for strings");
|
||||
|
Loading…
Reference in New Issue
Block a user