Ok. One more attempt with both tests fixed.

https://github.com/php/php-src/pull/1919


Nikita, you may take a look only into the last commit.

Do you see any other problems?

Sorry for abusing your time, but your feedback is extremely useful.


Thanks. Dmitry.

Thanks. Dmitry.

________________________________
From: Nikita Popov <nikita....@gmail.com>
Sent: Tuesday, May 24, 2016 1:12:31 AM
To: Dmitry Stogov
Cc: Xinchen Hui; internals
Subject: Re: "finally" handling refactoring (Bug #72213)

On Mon, May 23, 2016 at 11:36 PM, Dmitry Stogov 
<dmi...@zend.com<mailto:dmi...@zend.com>> wrote:

Hi,

On 05/23/2016 07:24 PM, Nikita Popov wrote:
On Mon, May 23, 2016 at 1:25 PM, Dmitry Stogov 
<dmi...@zend.com<mailto:dmi...@zend.com>> wrote:

Thanks for review.

Both problems should be fixed now 
<https://gist.github.com/dstogov/0a809891c6a3ac3fac4bd0d9711dd330> 
https://gist.github.com/dstogov/0a809891c6a3ac3fac4bd0d9711dd330

Do you see any other problems or a better way to fix this?

Your fix for DISCARD_EXCEPTION does not look right to me. It will discard all 
exceptions too early. For example:

function test() {
    try {
        throw new Exception(1);
    } finally {
        try {
            try {
            } finally {
                return 42;
            }
        } finally {
            throw new Exception(2);
        }
    }
}

test();

This will now not chain exception 1 and 2, because exception 1 is discarded at 
the return statement.

I thought about this, and I think that the current behavior is right.
If we remove "throw new Exception(2);" the first exception is going to be 
discarded at "return 42;".
I think we should do the same independently from the context.

Why do you think Exception(1) should be kept?

Because Exception(3) may be discarded by another catch in the finally, in which 
case we should throw Exception(1). Consider this case:

function test() {
    try {
        throw new Exception(1);
    } finally {
        try {
            try {
                try {
                } finally {
                    return 42;
                }
            } finally {
                throw new Exception(3);
            }
        } catch (Exception $e) {}
    }
}

test();

This should throw Exception(1), as Exception(3) is thrown and caught inside the 
finally block. I thought your current patch would not throw anything in this 
case, but I'm actually getting an assertion failure (and a conditional jump on 
uninit value in valgrind):

php: /home/nikic/php-src/Zend/zend_gc.c:226: gc_possible_root: Assertion 
`(ref)->gc.u.v.type == 7 || (ref)->gc.u.v.type == 8' failed.


I think this should be handled the same way we do the fast_call dispatch on 
return, i.e. when we pop the FAST_CALL from the loop var stack we should 
replace it with a DISCARD_EXCEPTION and then pop it after the finally. This 
should generate all the necessary DISCARD_EXCEPTION opcodes, and in the right 
order.

May be I'll commit the existing fix, and you'll try to implement this idea on 
top?

Thanks. Dmitry.


Nikita



Reply via email to