Fix finally exception chaining on recursion

In this case zend_exception_set_previous() would destroy the
fast_call exception and further accesses on ex would be invalid.
We should only update ex if we update EG(exception).

Fixes oss-fuzz #40464.
This commit is contained in:
Nikita Popov 2021-11-01 11:42:36 +01:00
parent 91dfac6f2a
commit 1a2fb90bf4
3 changed files with 20 additions and 4 deletions

View file

@ -0,0 +1,18 @@
--TEST--
Test case where the implicit previous finally exception would result in recursion
--FILE--
<?php
try {
$e = new Exception("M1");
try {
throw new Exception("M2", 0, $e);
} finally {
throw $e;
}
} finally {}
?>
--EXPECTF--
Fatal error: Uncaught Exception: M1 in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d

View file

@ -7714,9 +7714,8 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca
if (ex) { if (ex) {
zend_exception_set_previous(ex, Z_OBJ_P(fast_call)); zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
} else { } else {
EG(exception) = Z_OBJ_P(fast_call); ex = EG(exception) = Z_OBJ_P(fast_call);
} }
ex = Z_OBJ_P(fast_call);
} }
} }
} }

View file

@ -2905,9 +2905,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try
if (ex) { if (ex) {
zend_exception_set_previous(ex, Z_OBJ_P(fast_call)); zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
} else { } else {
EG(exception) = Z_OBJ_P(fast_call); ex = EG(exception) = Z_OBJ_P(fast_call);
} }
ex = Z_OBJ_P(fast_call);
} }
} }
} }