|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72188 Nested try/finally blocks losing return value
Submitted: 2016-05-10 19:11 UTC Modified: 2016-05-13 11:48 UTC
Avg. Score:4.0 ± 0.0
Reproduced:0 of 1 (0.0%)
From: lee at saferite dot com Assigned: dmitry (profile)
Status: Closed Package: Unknown/Other Function
PHP Version: 7.0.6 OS: Ubuntu 14.04
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
Solve the problem:
43 - 36 = ?
Subscribe to this entry?

 [2016-05-10 19:11 UTC] lee at saferite dot com
When you next a try/finally inside of a finally block it causes the return value from the outer try block to be lost.

Test script:

function test() {
    try {
        return 5;
    } finally {
        try {
            // NOOP
        } finally {
            // NOOP

$a = test();
if($a !== 5) {
    echo "FAILED: expected 5, received ", var_export($a), PHP_EOL;
} else {
    echo "Passed", PHP_EOL;

Expected result:
The call to test() should be seeing an int value of 5.

Actual result:
5.5.16-5.6.21 -- Works as expected
5.5.0-5.5.15 -- Exit code of 137 (SIGKILL)
7.0.0-7.0.6 -- The outer return value is lost and a null is returned.


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2016-05-11 07:20 UTC]
-Status: Open +Status: Verified -Assigned To: +Assigned To: laruence
 [2016-05-11 07:46 UTC]
fast_call in before finally overfide the return address set by the fast_call before zend_return.
 [2016-05-11 07:47 UTC]
-Assigned To: laruence +Assigned To: nikic
 [2016-05-11 07:48 UTC]
@nikic what do you think ? I don't see a easy to fix it..
 [2016-05-11 14:29 UTC]
So, as I understand it the problem is that the FAST_CALL<FROM_FINALLY> of the inner finally block will indiscriminately set the fast_call opline to the FAST_CALL of the outer finally block, even though this is not necessarily the FAST_CALL that was actually used to enter it (e.g. in this instance).

I was wondering why this worked on PHP 5.6 as IIRC the handling wasn't very different. It looks like it's just an accident of fate that this particular code works there. This similar example doesn't:

The only solution to this I see is to use different fast_call temporaries for each nesting level of finally-in-finally. We also need this to solve a similar issue with exceptions, though I can't seem to find the bug report for that just now (maybe in private discussions?).
 [2016-05-11 15:19 UTC]
-Assigned To: nikic +Assigned To: dmitry
 [2016-05-11 15:19 UTC]
the problem here is:

we have two entry to the outter finally, the one is FAST_CALL before return(1), and the other is FAST_CALL before finally(2).

when we enter the finally block via the `return` one, we set fast_call_var to ZEND_RETURN, but later, the ZEND_FAST_CALL in inner finally override it to its own return address.

later, when return from inner finally, it will return to the (2) which is calculated during compiling time.  thus bug shows up.

we could check fast_call_var's return address in ZEND_FAST_CALL to fix this particular problem, but the problem is, we allocate fast_call_var in temp var now, there is no initialization mechanism for it. which means, we can not do "check". 

@Dmitry, what do you think?

 [2016-05-13 11:39 UTC]
Automatic comment on behalf of
Log: Fixed bug #72188 (Nested try/finally blocks losing return value)
 [2016-05-13 11:39 UTC]
-Status: Verified +Status: Closed
 [2016-05-13 11:48 UTC]
Fixed in master (PHP-7.1) brunch only.
 [2016-07-20 11:31 UTC]
Automatic comment on behalf of
Log: Fixed bug #72188 (Nested try/finally blocks losing return value)
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed May 22 13:01:31 2024 UTC