diff options
Diffstat (limited to 'Zend')
| -rw-r--r-- | Zend/tests/bug30998.phpt | 4 | ||||
| -rw-r--r-- | Zend/tests/bug60909_1.phpt | 2 | ||||
| -rw-r--r-- | Zend/tests/bug63462.phpt | 74 | ||||
| -rw-r--r-- | Zend/tests/bug63882.phpt | 15 | ||||
| -rw-r--r-- | Zend/tests/bug63982.phpt | 15 | ||||
| -rw-r--r-- | Zend/zend_API.h | 4 | ||||
| -rw-r--r-- | Zend/zend_compile.c | 5 | ||||
| -rw-r--r-- | Zend/zend_language_parser.c | 4 | ||||
| -rw-r--r-- | Zend/zend_language_parser.y | 4 | ||||
| -rw-r--r-- | Zend/zend_object_handlers.c | 38 | ||||
| -rw-r--r-- | Zend/zend_objects_API.c | 1 | ||||
| -rw-r--r-- | Zend/zend_objects_API.h | 1 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 18 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 72 |
14 files changed, 170 insertions, 87 deletions
diff --git a/Zend/tests/bug30998.phpt b/Zend/tests/bug30998.phpt index d0ace9fa1..032da3d3b 100644 --- a/Zend/tests/bug30998.phpt +++ b/Zend/tests/bug30998.phpt @@ -15,7 +15,7 @@ $f = fopen("/tmp/blah", "r"); ?> ===DONE=== --EXPECTF-- -fopen(/tmp/blah): failed to open stream: No such file or directory (2) in %s:%d +fopen(/tmp/blah): failed to open stream: %s (2) in %s:%d -Warning: fopen(/tmp/blah): failed to open stream: No such file or directory in %s on line %d +Warning: fopen(/tmp/blah): failed to open stream: %s in %s on line %d ===DONE=== diff --git a/Zend/tests/bug60909_1.phpt b/Zend/tests/bug60909_1.phpt index 5150dfc02..cfe428928 100644 --- a/Zend/tests/bug60909_1.phpt +++ b/Zend/tests/bug60909_1.phpt @@ -10,7 +10,7 @@ set_error_handler(function($errno, $errstr, $errfile, $errline){ require 'notfound.php'; --EXPECTF-- -error(require(notfound.php): failed to open stream: No such file or directory) +error(require(notfound.php): failed to open stream: %s) Warning: Uncaught exception 'Exception' with message 'Foo' in %sbug60909_1.php:5 Stack trace: #0 %sbug60909_1.php(8): {closure}(2, 'require(notfoun...', '%s', 8, Array) diff --git a/Zend/tests/bug63462.phpt b/Zend/tests/bug63462.phpt new file mode 100644 index 000000000..e936a6fa6 --- /dev/null +++ b/Zend/tests/bug63462.phpt @@ -0,0 +1,74 @@ +--TEST-- +Test script to verify that magic methods should be called only once when accessing an unset property. +--CREDITS-- +Marco Pivetta <ocramius@gmail.com> +--FILE-- +<?php +class Test { + public $publicProperty; + protected $protectedProperty; + private $privateProperty; + + public function __construct() { + unset( + $this->publicProperty, + $this->protectedProperty, + $this->privateProperty + ); + } + + function __get($name) { + echo '__get ' . $name . "\n"; + return $this->$name; + } + + function __set($name, $value) { + echo '__set ' . $name . "\n"; + $this->$name = $value; + } + + function __isset($name) { + echo '__isset ' . $name . "\n"; + return isset($this->$name); + } +} + +$test = new Test(); + +$test->nonExisting; +$test->publicProperty; +$test->protectedProperty; +$test->privateProperty; +isset($test->nonExisting); +isset($test->publicProperty); +isset($test->protectedProperty); +isset($test->privateProperty); +$test->nonExisting = 'value'; +$test->publicProperty = 'value'; +$test->protectedProperty = 'value'; +$test->privateProperty = 'value'; + +?> + +--EXPECTF-- +__get nonExisting + +Notice: Undefined property: Test::$nonExisting in %s on line %d +__get publicProperty + +Notice: Undefined property: Test::$publicProperty in %s on line %d +__get protectedProperty + +Notice: Undefined property: Test::$protectedProperty in %s on line %d +__get privateProperty + +Notice: Undefined property: Test::$privateProperty in %s on line %d +__isset nonExisting +__isset publicProperty +__isset protectedProperty +__isset privateProperty +__set nonExisting +__set publicProperty +__set protectedProperty +__set privateProperty + diff --git a/Zend/tests/bug63882.phpt b/Zend/tests/bug63882.phpt new file mode 100644 index 000000000..0cc1babd4 --- /dev/null +++ b/Zend/tests/bug63882.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #63882 (zend_std_compare_objects crash on recursion) +--FILE-- +<?php +class Test { public $x = 5; } + +$testobj1 = new Test; +$testobj2 = new Test; +$testobj1->x = $testobj1; +$testobj2->x = $testobj2; + +var_dump($testobj1 == $testobj2); +?> +--EXPECTF-- +Fatal error: Nesting level too deep - recursive dependency? in %sbug63882.php on line 9 diff --git a/Zend/tests/bug63982.phpt b/Zend/tests/bug63982.phpt new file mode 100644 index 000000000..31294f33e --- /dev/null +++ b/Zend/tests/bug63982.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #63982 (isset() inconsistently produces a fatal error on protected property) +--FILE-- +<?php +class Test { + protected $protectedProperty; +} + +$test = new Test(); + +var_dump(isset($test->protectedProperty)); +var_dump(isset($test->protectedProperty->foo)); +--EXPECTF-- +bool(false) +bool(false) diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 4a3985e0f..ccbdf2c10 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -279,9 +279,9 @@ ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int ZEND_API int zend_register_class_alias_ex(const char *name, int name_len, zend_class_entry *ce TSRMLS_DC); #define zend_register_class_alias(name, ce) \ - zend_register_class_alias_ex(name, sizeof(name)-1, ce TSRMLS_DC) + zend_register_class_alias_ex(name, sizeof(name)-1, ce TSRMLS_CC) #define zend_register_ns_class_alias(ns, name, ce) \ - zend_register_class_alias_ex(ZEND_NS_NAME(ns, name), sizeof(ZEND_NS_NAME(ns, name))-1, ce TSRMLS_DC) + zend_register_class_alias_ex(ZEND_NS_NAME(ns, name), sizeof(ZEND_NS_NAME(ns, name))-1, ce TSRMLS_CC) ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC); ZEND_API int zend_disable_class(char *class_name, uint class_name_length TSRMLS_DC); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 32ee86afd..8f4f9c47b 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4795,10 +4795,11 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name /* Prefix class name with name of current namespace */ znode tmp; + tmp.op_type = IS_CONST; tmp.u.constant = *CG(current_namespace); zval_copy_ctor(&tmp.u.constant); zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC); - class_name = &tmp; + *class_name = tmp; efree(lcname); lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant)); } @@ -4931,7 +4932,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent } if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) - && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) { + && (parent_token || (ce->num_interfaces > 0))) { zend_verify_abstract_class(ce TSRMLS_CC); if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS)) { do_verify_abstract_class(TSRMLS_C); diff --git a/Zend/zend_language_parser.c b/Zend/zend_language_parser.c index 17af37976..295da98ca 100644 --- a/Zend/zend_language_parser.c +++ b/Zend/zend_language_parser.c @@ -3934,7 +3934,7 @@ yyreduce: case 102: - { zend_do_end_class_declaration(&(yyvsp[(1) - (8)]), &(yyvsp[(2) - (8)]) TSRMLS_CC); } + { zend_do_end_class_declaration(&(yyvsp[(1) - (8)]), &(yyvsp[(3) - (8)]) TSRMLS_CC); } break; case 103: @@ -3944,7 +3944,7 @@ yyreduce: case 104: - { zend_do_end_class_declaration(&(yyvsp[(1) - (7)]), &(yyvsp[(2) - (7)]) TSRMLS_CC); } + { zend_do_end_class_declaration(&(yyvsp[(1) - (7)]), NULL TSRMLS_CC); } break; case 105: diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index b37822903..1f5d73296 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -375,13 +375,13 @@ unticked_class_declaration_statement: implements_list '{' class_statement_list - '}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); } + '}' { zend_do_end_class_declaration(&$1, &$3 TSRMLS_CC); } | interface_entry T_STRING { zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); } interface_extends_list '{' class_statement_list - '}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); } + '}' { zend_do_end_class_declaration(&$1, NULL TSRMLS_CC); } ; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index a76dfb38a..cc45d35ec 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -35,6 +35,17 @@ #define Z_OBJ_P(zval_p) \ ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].bucket.obj.object)) +#define Z_OBJ_PROTECT_RECURSION(zval_p) \ + do { \ + if (EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].apply_count++ >= 3) { \ + zend_error(E_ERROR, "Nesting level too deep - recursive dependency?"); \ + } \ + } while (0) + + +#define Z_OBJ_UNPROTECT_RECURSION(zval_p) \ + EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].apply_count-- + /* __X accessors explanation: @@ -382,6 +393,16 @@ static int zend_get_property_guard(zend_object *zobj, zend_property_info *proper info.name = Z_STRVAL_P(member); info.name_length = Z_STRLEN_P(member); info.h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1); + } else if(property_info->name[0] == '\0'){ + const char *class_name = NULL, *prop_name = NULL; + zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name); + if(class_name) { + /* use unmangled name for protected properties */ + info.name = prop_name; + info.name_length = strlen(prop_name); + info.h = zend_get_hash_value(info.name, info.name_length+1); + property_info = &info; + } } if (!zobj->guards) { ALLOC_HASHTABLE(zobj->guards); @@ -424,7 +445,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li #endif /* make zend_get_property_info silent if we have getter - we may want to use it */ - property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC); + property_info = zend_get_property_info_quick(zobj->ce, member, silent || (zobj->ce->__get != NULL), key TSRMLS_CC); if (UNEXPECTED(!property_info) || ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && @@ -1319,28 +1340,43 @@ static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ } if (!zobj1->properties && !zobj2->properties) { int i; + + Z_OBJ_PROTECT_RECURSION(o1); + Z_OBJ_PROTECT_RECURSION(o2); for (i = 0; i < zobj1->ce->default_properties_count; i++) { if (zobj1->properties_table[i]) { if (zobj2->properties_table[i]) { zval result; if (compare_function(&result, zobj1->properties_table[i], zobj2->properties_table[i] TSRMLS_CC)==FAILURE) { + Z_OBJ_UNPROTECT_RECURSION(o1); + Z_OBJ_UNPROTECT_RECURSION(o2); return 1; } if (Z_LVAL(result) != 0) { + Z_OBJ_UNPROTECT_RECURSION(o1); + Z_OBJ_UNPROTECT_RECURSION(o2); return Z_LVAL(result); } } else { + Z_OBJ_UNPROTECT_RECURSION(o1); + Z_OBJ_UNPROTECT_RECURSION(o2); return 1; } } else { if (zobj2->properties_table[i]) { + Z_OBJ_UNPROTECT_RECURSION(o1); + Z_OBJ_UNPROTECT_RECURSION(o2); return 1; } else { + Z_OBJ_UNPROTECT_RECURSION(o1); + Z_OBJ_UNPROTECT_RECURSION(o2); return 0; } } } + Z_OBJ_UNPROTECT_RECURSION(o1); + Z_OBJ_UNPROTECT_RECURSION(o2); return 0; } else { if (!zobj1->properties) { diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 4f3561e3d..1fe5d0c19 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -117,6 +117,7 @@ ZEND_API zend_object_handle zend_objects_store_put(void *object, zend_objects_st obj = &EG(objects_store).object_buckets[handle].bucket.obj; EG(objects_store).object_buckets[handle].destructor_called = 0; EG(objects_store).object_buckets[handle].valid = 1; + EG(objects_store).object_buckets[handle].apply_count = 0; obj->refcount = 1; GC_OBJ_INIT(obj); diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index c973b7a20..a6ea9b8c0 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -31,6 +31,7 @@ typedef void (*zend_objects_store_clone_t)(void *object, void **object_clone TSR typedef struct _zend_object_store_bucket { zend_bool destructor_called; zend_bool valid; + zend_uchar apply_count; union _store_bucket { struct _store_object { void *object; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b7fa90707..e5cdd1d1f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -974,27 +974,15 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; - zval z_copy; zval *z; SAVE_OPLINE(); z = GET_OP1_ZVAL_PTR(BP_VAR_R); - if (OP1_TYPE != IS_CONST && - UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && - Z_OBJ_HT_P(z)->get_method != NULL) { - if (OP1_TYPE == IS_TMP_VAR) { - INIT_PZVAL(z); - } - if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - zend_print_variable(&z_copy); - zval_dtor(&z_copy); - } else { - zend_print_variable(z); - } - } else { - zend_print_variable(z); + if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) { + INIT_PZVAL(z); } + zend_print_variable(z); FREE_OP1(); CHECK_EXCEPTION(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 2680d8524..97e5a8e93 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2024,27 +2024,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval z_copy; zval *z; SAVE_OPLINE(); z = opline->op1.zv; - if (IS_CONST != IS_CONST && - UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && - Z_OBJ_HT_P(z)->get_method != NULL) { - if (IS_CONST == IS_TMP_VAR) { - INIT_PZVAL(z); - } - if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - zend_print_variable(&z_copy); - zval_dtor(&z_copy); - } else { - zend_print_variable(z); - } - } else { - zend_print_variable(z); + if (IS_CONST == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) { + INIT_PZVAL(z); } + zend_print_variable(z); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); @@ -6443,27 +6431,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1; - zval z_copy; zval *z; SAVE_OPLINE(); z = _get_zval_ptr_tmp(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (IS_TMP_VAR != IS_CONST && - UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && - Z_OBJ_HT_P(z)->get_method != NULL) { - if (IS_TMP_VAR == IS_TMP_VAR) { - INIT_PZVAL(z); - } - if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - zend_print_variable(&z_copy); - zval_dtor(&z_copy); - } else { - zend_print_variable(z); - } - } else { - zend_print_variable(z); + if (IS_TMP_VAR == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) { + INIT_PZVAL(z); } + zend_print_variable(z); zval_dtor(free_op1.var); CHECK_EXCEPTION(); @@ -10761,27 +10737,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_free_op free_op1; - zval z_copy; zval *z; SAVE_OPLINE(); z = _get_zval_ptr_var(opline->op1.var, EX_Ts(), &free_op1 TSRMLS_CC); - if (IS_VAR != IS_CONST && - UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && - Z_OBJ_HT_P(z)->get_method != NULL) { - if (IS_VAR == IS_TMP_VAR) { - INIT_PZVAL(z); - } - if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - zend_print_variable(&z_copy); - zval_dtor(&z_copy); - } else { - zend_print_variable(z); - } - } else { - zend_print_variable(z); + if (IS_VAR == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) { + INIT_PZVAL(z); } + zend_print_variable(z); if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; CHECK_EXCEPTION(); @@ -26741,27 +26705,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval z_copy; zval *z; SAVE_OPLINE(); z = _get_zval_ptr_cv_BP_VAR_R(EX_CVs(), opline->op1.var TSRMLS_CC); - if (IS_CV != IS_CONST && - UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) && - Z_OBJ_HT_P(z)->get_method != NULL) { - if (IS_CV == IS_TMP_VAR) { - INIT_PZVAL(z); - } - if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) { - zend_print_variable(&z_copy); - zval_dtor(&z_copy); - } else { - zend_print_variable(z); - } - } else { - zend_print_variable(z); + if (IS_CV == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) { + INIT_PZVAL(z); } + zend_print_variable(z); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); |
