summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
Diffstat (limited to 'Zend')
-rw-r--r--Zend/tests/bug30998.phpt4
-rw-r--r--Zend/tests/bug60909_1.phpt2
-rw-r--r--Zend/tests/bug63462.phpt74
-rw-r--r--Zend/tests/bug63882.phpt15
-rw-r--r--Zend/tests/bug63982.phpt15
-rw-r--r--Zend/zend_API.h4
-rw-r--r--Zend/zend_compile.c5
-rw-r--r--Zend/zend_language_parser.c4
-rw-r--r--Zend/zend_language_parser.y4
-rw-r--r--Zend/zend_object_handlers.c38
-rw-r--r--Zend/zend_objects_API.c1
-rw-r--r--Zend/zend_objects_API.h1
-rw-r--r--Zend/zend_vm_def.h18
-rw-r--r--Zend/zend_vm_execute.h72
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();