summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-07-09 20:47:25 +0300
committerDmitry Stogov <dmitry@zend.com>2015-07-09 20:47:25 +0300
commit17c5315bdf8f8087979aeb55f6d3a512ba197cf5 (patch)
tree7351d65a28af32587e436e73d25e8d87f3812b6c
parentd91aad5966f01259f0e1a431a754d917807761b5 (diff)
downloadphp-git-17c5315bdf8f8087979aeb55f6d3a512ba197cf5.tar.gz
Fixed exception habdling on "return" statement.
Such exceptions shouldn't be caught in the same function.
-rw-r--r--Zend/tests/return_types/029.phpt9
-rw-r--r--Zend/tests/return_types/030.phpt23
-rw-r--r--Zend/tests/temporary_cleaning_008.phpt42
-rw-r--r--Zend/tests/temporary_cleaning_009.phpt29
-rw-r--r--Zend/zend_opcode.c3
-rw-r--r--Zend/zend_vm_def.h19
-rw-r--r--Zend/zend_vm_execute.h31
7 files changed, 150 insertions, 6 deletions
diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt
index 37587452f5..c854456a6b 100644
--- a/Zend/tests/return_types/029.phpt
+++ b/Zend/tests/return_types/029.phpt
@@ -8,12 +8,15 @@ function foo(): string {
try {
return $class; // invalid return type
} catch (TypeError $e) {
- return "no leak or segfault";
+ return "BAG!";
}
}
}
-print foo();
-
+try {
+ print foo();
+} catch (TypeError $e) {
+ print "no leak or segfault";
+}
?>
--EXPECT--
no leak or segfault
diff --git a/Zend/tests/return_types/030.phpt b/Zend/tests/return_types/030.phpt
new file mode 100644
index 0000000000..73b512ed14
--- /dev/null
+++ b/Zend/tests/return_types/030.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Return types must not double free loop variables
+--FILE--
+<?php
+
+function foo(): string {
+ $a = [];
+ try {
+ return $a; // invalid return type
+ } catch (TypeError $e) {
+ echo "BAG!\n";
+ return "ops!\n";
+ }
+}
+try {
+ echo foo();
+} catch (TypeError $e) {
+ echo "OK\n";
+}
+
+?>
+--EXPECT--
+OK
diff --git a/Zend/tests/temporary_cleaning_008.phpt b/Zend/tests/temporary_cleaning_008.phpt
new file mode 100644
index 0000000000..cbbbc6cd6c
--- /dev/null
+++ b/Zend/tests/temporary_cleaning_008.phpt
@@ -0,0 +1,42 @@
+--TEST--
+Exception inside a foreach loop with on an object with destructor
+--FILE--
+<?php
+class bar {
+ public $foo = 1;
+ public $bar = 2;
+ function __destruct() {
+ throw new Exception("test");
+ }
+}
+function foo(): string {
+ foreach (new bar() as $foo) {
+ try {
+ $foo = new Exception;
+ return;
+ } catch (Exception $e) {
+ echo "Exception1: " . $e->getMessage() . "\n";
+ } catch (Error $e) {
+ echo "Error1: " . $e->getMessage() . "\n";
+ }
+ }
+ echo "bag!\n";
+}
+try {
+ foo();
+} catch (Throwable $e) {
+ echo (($e instanceof Exception) ? "Exception2: " : "Error2: ") .
+ $e->getMessage() . "\n";
+ $e = $e->getPrevious();
+ while ($e instanceof Throwable) {
+ echo "\tPrev " . (($e instanceof Exception) ? "Exception2: " : "Error2: ") .
+ $e->getMessage() . "\n";
+ $e = $e->getPrevious();
+ }
+}
+echo "ok\n";
+?>
+--EXPECTF--
+Exception2: test
+ Prev Error2: Return value of foo() must be of the type string, none returned in %stemporary_cleaning_008.php on line %d
+ok
diff --git a/Zend/tests/temporary_cleaning_009.phpt b/Zend/tests/temporary_cleaning_009.phpt
new file mode 100644
index 0000000000..c6f747edb5
--- /dev/null
+++ b/Zend/tests/temporary_cleaning_009.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Exception inside a foreach loop with on an object with destructor
+--FILE--
+<?php
+class bar {
+ public $foo = 1;
+ function __destruct() {
+ throw new Exception;
+ }
+}
+
+function foo() {
+ foreach (new bar() as &$foo) {
+ try {
+ $foo = new Exception;
+ return;
+ } catch (Exception $e) {
+ echo "Exception1\n";
+ }
+ }
+}
+try {
+ foo();
+} catch (Exception $e) {
+ echo "Exception2\n";
+}
+?>
+--EXPECT--
+Exception2
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 64ba6562ff..e84edd54b9 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -992,7 +992,8 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra
&& opline->opcode != ZEND_CASE
&& opline->opcode != ZEND_FE_FETCH_R
&& opline->opcode != ZEND_FE_FETCH_RW
- /* the following opcodes are not the "final" */
+ /* the following opcodes are parts of "return" statement */
+ && opline->opcode != ZEND_VERIFY_RETURN_TYPE
&& (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
&& (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN))
) {
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 8744bf315a..9b36b804c9 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2610,10 +2610,13 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, ANY)
ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY)
{
+ zval *var;
USE_OPLINE
SAVE_OPLINE();
- zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+ var = EX_VAR(opline->op1.var);
+ zval_ptr_dtor_nogc(var);
+ ZVAL_NULL(var);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
@@ -2626,8 +2629,10 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
var = EX_VAR(opline->op1.var);
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
zend_hash_iterator_del(Z_FE_ITER_P(var));
+ Z_FE_ITER_P(var) = (uint32_t)-1;
}
zval_ptr_dtor_nogc(var);
+ ZVAL_NULL(var);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
@@ -3883,6 +3888,9 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED)
if (UNEXPECTED(EG(exception) != NULL)) {
FREE_OP1();
+ if (OP1_TYPE == IS_TMP_VAR || OP1_TYPE == IS_VAR) {
+ ZVAL_NULL(retval_ref);
+ }
}
#endif
}
@@ -7074,6 +7082,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
}
}
+ if (catch_op_num || finally_op_num) {
+ if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE
+ || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
+ || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
+ ) {
+ catch_op_num = finally_op_num = 0;
+ }
+ }
+
i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index c45d2ee3c9..6089b2e3c4 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1500,6 +1500,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
}
}
+ if (catch_op_num || finally_op_num) {
+ if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE
+ || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
+ || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN))
+ ) {
+ catch_op_num = finally_op_num = 0;
+ }
+ }
+
i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num);
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
@@ -7740,6 +7749,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
if (UNEXPECTED(EG(exception) != NULL)) {
+ if (IS_CONST == IS_TMP_VAR || IS_CONST == IS_VAR) {
+ ZVAL_NULL(retval_ref);
+ }
}
#endif
}
@@ -13536,6 +13548,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor_nogc(free_op1);
+ if (IS_TMP_VAR == IS_TMP_VAR || IS_TMP_VAR == IS_VAR) {
+ ZVAL_NULL(retval_ref);
+ }
}
#endif
}
@@ -19225,6 +19240,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
if (UNEXPECTED(EG(exception) != NULL)) {
zval_ptr_dtor_nogc(free_op1);
+ if (IS_VAR == IS_TMP_VAR || IS_VAR == IS_VAR) {
+ ZVAL_NULL(retval_ref);
+ }
}
#endif
}
@@ -24910,6 +24928,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
if (UNEXPECTED(EG(exception) != NULL)) {
+ if (IS_UNUSED == IS_TMP_VAR || IS_UNUSED == IS_VAR) {
+ ZVAL_NULL(retval_ref);
+ }
}
#endif
}
@@ -34346,6 +34367,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
if (UNEXPECTED(EG(exception) != NULL)) {
+ if (IS_CV == IS_TMP_VAR || IS_CV == IS_VAR) {
+ ZVAL_NULL(retval_ref);
+ }
}
#endif
}
@@ -40164,10 +40188,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_TMPVAR_HANDLER(Z
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
+ zval *var;
USE_OPLINE
SAVE_OPLINE();
- zval_ptr_dtor_nogc(EX_VAR(opline->op1.var));
+ var = EX_VAR(opline->op1.var);
+ zval_ptr_dtor_nogc(var);
+ ZVAL_NULL(var);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}
@@ -40180,8 +40207,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZE
var = EX_VAR(opline->op1.var);
if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) {
zend_hash_iterator_del(Z_FE_ITER_P(var));
+ Z_FE_ITER_P(var) = (uint32_t)-1;
}
zval_ptr_dtor_nogc(var);
+ ZVAL_NULL(var);
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}