]> granicus.if.org Git - php/commitdiff
Fixed bug #73288 (Segfault in __clone > Exception.toString > __get)
authorXinchen Hui <laruence@gmail.com>
Wed, 12 Oct 2016 08:07:56 +0000 (16:07 +0800)
committerXinchen Hui <laruence@gmail.com>
Wed, 12 Oct 2016 08:07:56 +0000 (16:07 +0800)
Actually this is caused by optimization(opcache)

NEWS
Zend/tests/bug73288.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index 6268c540496dddb89ffa49830b6794be9d60f7d8..a9cebe9dcca4364de74fb0f0f5a9e8aebabb07a5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ PHP                                                                        NEWS
 ?? ??? 2016, PHP 7.1.0RC4
 
 - Core:
+  . Fixed bug #73288 (Segfault in __clone > Exception.toString > __get).
+    (Laruence)
   . Implemented RFC: get_class() disallow null parameter. Passing null to
     get_class() now generates a warning, rather than returning the calling
     class scope.
diff --git a/Zend/tests/bug73288.phpt b/Zend/tests/bug73288.phpt
new file mode 100644 (file)
index 0000000..fefcf3b
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+Bug #73288 (Segfault in __clone > Exception.toString > __get)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--FILE--
+<?php
+
+class NoClone {
+       public function __clone() {
+               throw new Exception("No Cloneable");
+       }
+}
+
+class C {
+       public function __get($name) {
+               return new NoClone;
+       }
+}
+
+function test_clone() {
+       $c = new C;
+       $b = clone $c->x;
+}
+
+test_clone();
+?>
+--EXPECTF--
+Fatal error: Uncaught Exception: No Cloneable in %sbug73288.php:%d
+Stack trace:
+#0 %s(%d): NoClone->__clone()
+#1 %s(%d): test_clone()
+#2 {main}
+  thrown in %sbug73288.php on line %d
index 7bad61dd2c1f4789a1fc9c4f1a0cb6584a4a76c8..c5dc3256a0aafdca090a43f065d447990e55d3ba 100644 (file)
@@ -5000,6 +5000,7 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
        USE_OPLINE
        zend_free_op free_op1;
        zval *obj;
+       zend_object *clone_obj;
        zend_class_entry *ce, *scope;
        zend_function *clone;
        zend_object_clone_obj_t clone_call;
@@ -5064,9 +5065,11 @@ ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
                }
        }
 
-       ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(obj));
-       if (UNEXPECTED(EG(exception) != NULL)) {
-               OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
+       clone_obj = clone_call(obj);
+       if (EXPECTED(EG(exception) == NULL)) {
+               ZVAL_OBJ(EX_VAR(opline->result.var), clone_obj);
+       } else {
+               OBJ_RELEASE(clone_obj);
        }
 
        FREE_OP1();
index 677a2175269dc5051119d52e4f1bb0ee26adefd5..61e63fad464866752d34617dc50a2a1f92f30494 100644 (file)
@@ -3231,6 +3231,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_
        USE_OPLINE
 
        zval *obj;
+       zend_object *clone_obj;
        zend_class_entry *ce, *scope;
        zend_function *clone;
        zend_object_clone_obj_t clone_call;
@@ -3295,9 +3296,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CONST_HANDLER(ZEND_
                }
        }
 
-       ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(obj));
-       if (UNEXPECTED(EG(exception) != NULL)) {
-               OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
+       clone_obj = clone_call(obj);
+       if (EXPECTED(EG(exception) == NULL)) {
+               ZVAL_OBJ(EX_VAR(opline->result.var), clone_obj);
+       } else {
+               OBJ_RELEASE(clone_obj);
        }
 
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
@@ -27784,6 +27787,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND
        USE_OPLINE
 
        zval *obj;
+       zend_object *clone_obj;
        zend_class_entry *ce, *scope;
        zend_function *clone;
        zend_object_clone_obj_t clone_call;
@@ -27848,9 +27852,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_UNUSED_HANDLER(ZEND
                }
        }
 
-       ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(obj));
-       if (UNEXPECTED(EG(exception) != NULL)) {
-               OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
+       clone_obj = clone_call(obj);
+       if (EXPECTED(EG(exception) == NULL)) {
+               ZVAL_OBJ(EX_VAR(opline->result.var), clone_obj);
+       } else {
+               OBJ_RELEASE(clone_obj);
        }
 
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
@@ -35107,6 +35113,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC
        USE_OPLINE
 
        zval *obj;
+       zend_object *clone_obj;
        zend_class_entry *ce, *scope;
        zend_function *clone;
        zend_object_clone_obj_t clone_call;
@@ -35171,9 +35178,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_CV_HANDLER(ZEND_OPC
                }
        }
 
-       ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(obj));
-       if (UNEXPECTED(EG(exception) != NULL)) {
-               OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
+       clone_obj = clone_call(obj);
+       if (EXPECTED(EG(exception) == NULL)) {
+               ZVAL_OBJ(EX_VAR(opline->result.var), clone_obj);
+       } else {
+               OBJ_RELEASE(clone_obj);
        }
 
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
@@ -51305,6 +51314,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND
        USE_OPLINE
        zend_free_op free_op1;
        zval *obj;
+       zend_object *clone_obj;
        zend_class_entry *ce, *scope;
        zend_function *clone;
        zend_object_clone_obj_t clone_call;
@@ -51369,9 +51379,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CLONE_SPEC_TMPVAR_HANDLER(ZEND
                }
        }
 
-       ZVAL_OBJ(EX_VAR(opline->result.var), clone_call(obj));
-       if (UNEXPECTED(EG(exception) != NULL)) {
-               OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
+       clone_obj = clone_call(obj);
+       if (EXPECTED(EG(exception) == NULL)) {
+               ZVAL_OBJ(EX_VAR(opline->result.var), clone_obj);
+       } else {
+               OBJ_RELEASE(clone_obj);
        }
 
        zval_ptr_dtor_nogc(free_op1);