]> granicus.if.org Git - php/commitdiff
Fix handling of throwing undef var in verify return
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 13 Oct 2020 09:38:30 +0000 (11:38 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 13 Oct 2020 09:43:43 +0000 (11:43 +0200)
If we have an undefined variable and null is not accepted by the
return type, we want to throw just the undef var error.

In this case this lead to an infinite loop, because we overwrite
the exception opline in SAVE_OPLINE and it does not get reset
when chaining into a previous exception. Add an assertiong to
catch this case earlier.

Zend/tests/undef_var_in_verify_return.phpt [new file with mode: 0644]
Zend/zend_exceptions.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/undef_var_in_verify_return.phpt b/Zend/tests/undef_var_in_verify_return.phpt
new file mode 100644 (file)
index 0000000..b8c263c
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+Throwing undef var in verify return
+--FILE--
+<?php
+
+set_error_handler(function(int $severity, string $message, string $filename, int $lineNumber): void {
+    throw new ErrorException($message, 0, $severity, $filename, $lineNumber);
+});
+
+function test(): string {
+    return $test;
+}
+
+test();
+
+?>
+--EXPECTF--
+Fatal error: Uncaught ErrorException: Undefined variable $test in %s:%d
+Stack trace:
+#0 %s(%d): {closure}(2, 'Undefined varia...', '%s', 8)
+#1 %s(%d): test()
+#2 {main}
+  thrown in %s on line %d
index f037f0399a11eb5ef43a7caafd00e04d231d9e35..b52b1ab113ecb1ed95c25f3255a1f0ab64b4388c 100644 (file)
@@ -144,6 +144,13 @@ void zend_exception_restore(void) /* {{{ */
 }
 /* }}} */
 
+static zend_always_inline zend_bool is_handle_exception_set() {
+       zend_execute_data *execute_data = EG(current_execute_data);
+       return !execute_data->func
+               || !ZEND_USER_CODE(execute_data->func->common.type)
+               || execute_data->opline->opcode == ZEND_HANDLE_EXCEPTION;
+}
+
 ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* {{{ */
 {
 #ifdef HAVE_DTRACE
@@ -161,6 +168,7 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /*
                zend_exception_set_previous(exception, EG(exception));
                EG(exception) = exception;
                if (previous) {
+                       ZEND_ASSERT(is_handle_exception_set() && "HANDLE_EXCEPTION not set?");
                        return;
                }
        }
@@ -179,9 +187,7 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /*
                zend_throw_exception_hook(exception);
        }
 
-       if (!EG(current_execute_data)->func ||
-           !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
-           EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) {
+       if (is_handle_exception_set()) {
                /* no need to rethrow the exception */
                return;
        }
index d647dddeab03dab980205423fdf0852dbe99c0f6..cff1012acae923958378b58cccd397d586b3afbc 100644 (file)
@@ -4195,8 +4195,11 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
                if (OP1_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
                        SAVE_OPLINE();
                        retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
                        if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
                }
 
index 27d1ee15719a77961185276aa4d82122fc1953fe..1786cfcc83a91694dcbc9d680474591d0331a6cb 100644 (file)
@@ -9707,8 +9707,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYP
                if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
                        SAVE_OPLINE();
                        retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
                        if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
                }
 
@@ -20051,8 +20054,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN
                if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
                        SAVE_OPLINE();
                        retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
                        if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
                }
 
@@ -27656,8 +27662,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN
                if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
                        SAVE_OPLINE();
                        retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
                        if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
                }
 
@@ -34853,8 +34862,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED
                if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
                        SAVE_OPLINE();
                        retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
                        if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
                }
 
@@ -46545,8 +46557,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU
                if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
                        SAVE_OPLINE();
                        retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
+                       if (UNEXPECTED(EG(exception))) {
+                               HANDLE_EXCEPTION();
+                       }
                        if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
-                               ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
+                               ZEND_VM_NEXT_OPCODE();
                        }
                }