]> granicus.if.org Git - php/commitdiff
Fix leak when setting cyclic previous exception in finally
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 30 Jun 2020 10:22:41 +0000 (12:22 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 30 Jun 2020 10:24:32 +0000 (12:24 +0200)
A curious exception handling pattern found in Symfony's HttpClient.

Zend/tests/exception_set_previous_leak.phpt [new file with mode: 0644]
Zend/zend_exceptions.c

diff --git a/Zend/tests/exception_set_previous_leak.phpt b/Zend/tests/exception_set_previous_leak.phpt
new file mode 100644 (file)
index 0000000..7fb680f
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Leak when setting recursive previous exception in finally handling
+--FILE--
+<?php
+
+try {
+    try {
+        throw new Exception("Test");
+    } catch (Exception $e) {
+        throw $e;
+    } finally {
+        throw $e;
+    }
+} catch (Exception $e2) {
+    echo $e2->getMessage(), "\n";
+}
+
+?>
+--EXPECT--
+Test
index 3ad5748e4dd7fdab760245427d4a2d862f767a5a..371c38dcd6c336b6bf5e91f061862fece96479ee 100644 (file)
@@ -76,9 +76,15 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
        zval  pv, zv, rv;
        zend_class_entry *base_ce;
 
-       if (exception == add_previous || !add_previous || !exception) {
+       if (!exception || !add_previous) {
                return;
        }
+
+       if (exception == add_previous) {
+               OBJ_RELEASE(add_previous);
+               return;
+       }
+
        ZVAL_OBJ(&pv, add_previous);
        if (!instanceof_function(Z_OBJCE(pv), zend_ce_throwable)) {
                zend_error_noreturn(E_CORE_ERROR, "Previous exception must implement Throwable");