From e63febb1c772e15c1da891f00e3a343090e43c67 Mon Sep 17 00:00:00 2001 From: David Walker Date: Wed, 14 Feb 2018 22:06:34 -0700 Subject: [PATCH] Fixed bug #75921 Ensure that the "creating default object from empty value" warning is always thrown. Previously some cases were missing the warning, in particular those going through FETCH_OBJ_W rather than a dedicated opcode (like ASSIGN_OBJ). One slightly unfortunate side-effect of this change is that something like $a->b->c = 'd' will now generate two warnings rather than one when $a is null (one for property b, one for property c). --- NEWS | 2 + Zend/tests/bug52041.phpt | 6 ++ Zend/tests/bug71539_5.phpt | 3 +- Zend/tests/bug75921.phpt | 80 +++++++++++++++++++ Zend/tests/objects_020.phpt | 1 + .../typed_properties_091.phpt | 4 + Zend/zend_execute.c | 38 ++------- ext/simplexml/tests/bug36611.phpt | 8 +- .../lang/engine_assignExecutionOrder_008.phpt | 8 +- tests/lang/foreachLoop.016.phpt | 8 ++ tests/lang/passByReference_006.phpt | 48 +++++++++++ 11 files changed, 168 insertions(+), 38 deletions(-) create mode 100644 Zend/tests/bug75921.phpt diff --git a/NEWS b/NEWS index 2902141140..35680aefcf 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ PHP NEWS specially compiled functions). (Majkl578) . Fixed bug #76430 (__METHOD__ inconsistent outside of method). (Ryan McCullagh, Nikita) + . Fixed bug #75921 (Inconsistent: No warning in some cases when stdObj is + created on the fly). (David Walker) - CURL: . Fixed bug #76480 (Use curl_multi_wait() so that timeouts are respected). diff --git a/Zend/tests/bug52041.phpt b/Zend/tests/bug52041.phpt index 7e1f3423a6..a1eb1f841b 100644 --- a/Zend/tests/bug52041.phpt +++ b/Zend/tests/bug52041.phpt @@ -31,6 +31,8 @@ Notice: Undefined variable: x in %sbug52041.php on line 3 Warning: Creating default object from empty value in %sbug52041.php on line 7 +Warning: Creating default object from empty value in %sbug52041.php on line 7 + Notice: Undefined variable: x in %sbug52041.php on line 3 Warning: Creating default object from empty value in %sbug52041.php on line 8 @@ -39,6 +41,8 @@ Notice: Undefined property: stdClass::$a in %sbug52041.php on line 8 Notice: Undefined variable: x in %sbug52041.php on line 3 +Warning: Creating default object from empty value in %sbug52041.php on line 9 + Notice: Undefined property: stdClass::$a in %sbug52041.php on line 9 Warning: Creating default object from empty value in %sbug52041.php on line 9 @@ -53,6 +57,8 @@ Notice: Undefined property: stdClass::$a in %sbug52041.php on line 10 Notice: Undefined variable: x in %sbug52041.php on line 3 +Warning: Creating default object from empty value in %sbug52041.php on line 11 + Notice: Undefined property: stdClass::$a in %sbug52041.php on line 11 Warning: Creating default object from empty value in %sbug52041.php on line 11 diff --git a/Zend/tests/bug71539_5.phpt b/Zend/tests/bug71539_5.phpt index 14559bf65e..7e89971ec2 100644 --- a/Zend/tests/bug71539_5.phpt +++ b/Zend/tests/bug71539_5.phpt @@ -7,7 +7,8 @@ $array['']->prop =& $array[0]; $array[0] = 42; var_dump($array); ?> ---EXPECT-- +--EXPECTF-- +Warning: Creating default object from empty value in %sbug71539_5.php on line 3 array(2) { [0]=> &int(42) diff --git a/Zend/tests/bug75921.phpt b/Zend/tests/bug75921.phpt new file mode 100644 index 0000000000..917dd413cc --- /dev/null +++ b/Zend/tests/bug75921.phpt @@ -0,0 +1,80 @@ +--TEST-- +Bug #75921: Inconsistent error when creating stdObject from empty variable +--FILE-- +a = 42; +var_dump($null); +unset($null); + +$null->a['hello'] = 42; +var_dump($null); +unset($null); + +$null->a->b = 42; +var_dump($null); +unset($null); + +$null->a['hello']->b = 42; +var_dump($null); +unset($null); + +$null->a->b['hello'] = 42; +var_dump($null); +unset($null); + +?> +--EXPECTF-- +Warning: Creating default object from empty value in %sbug75921.php on line 3 +object(stdClass)#1 (1) { + ["a"]=> + int(42) +} + +Warning: Creating default object from empty value in %sbug75921.php on line 7 +object(stdClass)#1 (1) { + ["a"]=> + array(1) { + ["hello"]=> + int(42) + } +} + +Warning: Creating default object from empty value in %sbug75921.php on line 11 + +Warning: Creating default object from empty value in %sbug75921.php on line 11 +object(stdClass)#1 (1) { + ["a"]=> + object(stdClass)#2 (1) { + ["b"]=> + int(42) + } +} + +Warning: Creating default object from empty value in %sbug75921.php on line 15 + +Warning: Creating default object from empty value in %sbug75921.php on line 15 +object(stdClass)#1 (1) { + ["a"]=> + array(1) { + ["hello"]=> + object(stdClass)#2 (1) { + ["b"]=> + int(42) + } + } +} + +Warning: Creating default object from empty value in %sbug75921.php on line 19 + +Warning: Creating default object from empty value in %sbug75921.php on line 19 +object(stdClass)#1 (1) { + ["a"]=> + object(stdClass)#2 (1) { + ["b"]=> + array(1) { + ["hello"]=> + int(42) + } + } +} diff --git a/Zend/tests/objects_020.phpt b/Zend/tests/objects_020.phpt index 14e34b9155..4b0e0d1ec7 100644 --- a/Zend/tests/objects_020.phpt +++ b/Zend/tests/objects_020.phpt @@ -14,6 +14,7 @@ var_dump($$test); ?> --EXPECTF-- +Warning: Creating default object from empty value in %sobjects_020.php on line 7 object(stdClass)#%d (2) { ["a"]=> *RECURSION* diff --git a/Zend/tests/type_declarations/typed_properties_091.phpt b/Zend/tests/type_declarations/typed_properties_091.phpt index 7d6b54ae59..2083086086 100644 --- a/Zend/tests/type_declarations/typed_properties_091.phpt +++ b/Zend/tests/type_declarations/typed_properties_091.phpt @@ -134,6 +134,10 @@ Cannot auto-initialize an stdClass inside a reference held by property Test::$pr Warning: Creating default object from empty value in %s on line %d +Warning: Creating default object from empty value in %s on line %d + +Warning: Creating default object from empty value in %s on line %d + Warning: Creating default object from empty value in %s on line %d object(Test)#3 (3) { ["prop"]=> diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 2c7a4512a2..7fb7e44792 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -709,6 +709,10 @@ static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL make_real_object(zval *ob || opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) { zend_error(E_WARNING, "Attempt to increment/decrement property '%s' of non-object", ZSTR_VAL(property_name)); + } else if (opline->opcode == ZEND_FETCH_OBJ_W + || opline->opcode == ZEND_FETCH_OBJ_RW + || opline->opcode == ZEND_ASSIGN_OBJ_REF) { + zend_error(E_WARNING, "Attempt to modify property '%s' of non-object", ZSTR_VAL(property_name)); } else { zend_error(E_WARNING, "Attempt to assign property '%s' of non-object", ZSTR_VAL(property_name)); } @@ -748,38 +752,6 @@ static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL make_real_object(zval *ob return object; } -static zend_never_inline ZEND_COLD zval* ZEND_FASTCALL make_real_object_rw(zval *object, zval *property OPLINE_DC) -{ - zval *ref = NULL; - if (Z_ISREF_P(object)) { - ref = object; - object = Z_REFVAL_P(object); - } - - if (UNEXPECTED(Z_TYPE_P(object) > IS_FALSE && - (Z_TYPE_P(object) != IS_STRING || Z_STRLEN_P(object) != 0))) { - if (opline->op1_type != IS_VAR || EXPECTED(!Z_ISERROR_P(object))) { - zend_string *tmp_property_name; - zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name); - zend_error(E_WARNING, "Attempt to modify property '%s' of non-object", ZSTR_VAL(property_name)); - zend_tmp_string_release(tmp_property_name); - } - return NULL; - } - - if (ref) { - zend_property_info *error_prop = i_zend_check_ref_stdClass_assignable(Z_REF_P(ref)); - if (error_prop) { - zend_throw_auto_init_in_ref_error(error_prop, "stdClass"); - return NULL; - } - } - - zval_ptr_dtor_nogc(object); - object_init(object); - return object; -} - static ZEND_COLD void zend_verify_type_error_common( const zend_function *zf, const zend_arg_info *arg_info, const zend_class_entry *ce, zval *value, @@ -2736,7 +2708,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c return; } - container = make_real_object_rw(container, prop_ptr OPLINE_CC); + container = make_real_object(container, prop_ptr OPLINE_CC); if (UNEXPECTED(!container)) { ZVAL_ERROR(result); return; diff --git a/ext/simplexml/tests/bug36611.phpt b/ext/simplexml/tests/bug36611.phpt index eb202671ca..d9c2a049b5 100644 --- a/ext/simplexml/tests/bug36611.phpt +++ b/ext/simplexml/tests/bug36611.phpt @@ -14,17 +14,19 @@ $xml_str = << EOD; -$xml = simplexml_load_string ($xml_str) ; +$xml = simplexml_load_string($xml_str); $val = 1; var_dump($val); $zml->pos["act_idx"] = $val; -var_dump($val) ; +var_dump($val); ?> ===DONE=== ---EXPECT-- +--EXPECTF-- int(1) + +Warning: Creating default object from empty value in %sbug36611.php on line 17 int(1) ===DONE=== diff --git a/tests/lang/engine_assignExecutionOrder_008.phpt b/tests/lang/engine_assignExecutionOrder_008.phpt index be9b3423c8..310e0d9964 100644 --- a/tests/lang/engine_assignExecutionOrder_008.phpt +++ b/tests/lang/engine_assignExecutionOrder_008.phpt @@ -70,9 +70,15 @@ Warning: Creating default object from empty value in %s on line %d good $i->p->q=f(): Warning: Creating default object from empty value in %s on line %d + +Warning: Creating default object from empty value in %s on line %d +good +$i->p[0]=f(): +Warning: Creating default object from empty value in %s on line %d good -$i->p[0]=f(): good $i->p[0]->p=f(): +Warning: Creating default object from empty value in %s on line %d + Warning: Creating default object from empty value in %s on line %d good C::$p=f(): good diff --git a/tests/lang/foreachLoop.016.phpt b/tests/lang/foreachLoop.016.phpt index 00deb5f1db..fa1267fa8d 100644 --- a/tests/lang/foreachLoop.016.phpt +++ b/tests/lang/foreachLoop.016.phpt @@ -157,6 +157,8 @@ array(1) { $a->b->c +Warning: Creating default object from empty value in %s on line %d + Warning: Creating default object from empty value in %s on line %d array(1) { [0]=> @@ -164,12 +166,16 @@ array(1) { } $a->b[0] + +Warning: Creating default object from empty value in %s on line %d array(1) { [0]=> string(8) "original" } $a->b[0][0] + +Warning: Creating default object from empty value in %s on line %d array(1) { [0]=> string(8) "original" @@ -177,6 +183,8 @@ array(1) { $a->b[0]->c +Warning: Creating default object from empty value in %s on line %d + Warning: Creating default object from empty value in %s on line %d array(1) { [0]=> diff --git a/tests/lang/passByReference_006.phpt b/tests/lang/passByReference_006.phpt index 9f5d275333..c1478663ca 100644 --- a/tests/lang/passByReference_006.phpt +++ b/tests/lang/passByReference_006.phpt @@ -55,6 +55,18 @@ var_dump($u1, $u2, $u3, $u4, $u5); ?> --EXPECTF-- ---- Pass uninitialised array & object by ref: function call --- + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d array(1) { [0]=> string(12) "Ref1 changed" @@ -91,6 +103,18 @@ object(stdClass)#%d (1) { ---- Pass uninitialised arrays & objects by ref: static method call --- Deprecated: Non-static method C::refs() should not be called statically in %s on line 39 + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d array(1) { [0]=> string(12) "Ref1 changed" @@ -126,6 +150,18 @@ object(stdClass)#%d (1) { ---- Pass uninitialised arrays & objects by ref: constructor --- + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d array(1) { [0]=> string(12) "Ref1 changed" @@ -160,6 +196,18 @@ object(stdClass)#%d (1) { } ---- Pass uninitialised arrays & objects by ref: instance method call --- + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d + +Warning: Creating default object from empty value in %spassByReference_006.php on line %d array(1) { [0]=> string(12) "Ref1 changed" -- 2.50.0