php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #65665 Exception not properly caught when opcache enabled
Submitted: 2013-09-13 00:15 UTC Modified: 2013-09-15 06:06 UTC
From: ryan dot brothers at gmail dot com Assigned: dmitry (profile)
Status: Closed Package: opcache
PHP Version: 5.5.3 OS: Linux
Private report: No CVE-ID: None
 [2013-09-13 00:15 UTC] ryan dot brothers at gmail dot com
Description:
------------
When running the following script with opcache enabled, the exception is not caught by the correct catch block.  The exception should be caught by the 'caught by 1' block, but it is instead caught by the 'caught by 2' block.  Disabling opcache causes the exception to be caught in the correct block.

Run the script with:

php -n -d zend_extension=opcache.so -d opcache.enable_cli=1 script.php


Test script:
---------------
<?php
try
{
    switch (1)
    {
        case 0:
            try
            {

            }
            catch (Exception $e)
            {

            }

            break;

        case 1:
            try
            {
                throw new Exception('aaa');
            }
            catch (Exception $e)
            {
                echo 'caught by 1';
                exit;
            }

            break;
    }
}
catch (Exception $e)
{
    echo 'caught by 2';
    exit;
}


Expected result:
----------------
caught by 1

Actual result:
--------------
caught by 2

Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-09-13 15:31 UTC] jpauli@php.net
This is an optimizer bug.
If you run with opcache.optimization_level=0 , the bug disappears.

I guess the bug is in the optimizer pass that handles ZEND_CATCH.
PS : I reproduced with a 5.4 base.
 [2013-09-13 17:16 UTC] Danack at basereality dot com
Running with -d opcache.optimization_level=0xfffffffd shows the correct behaviour. 
That flag is the equivalent to turning on all optimizations except:

'ZEND_OPTIMIZER_PASS_2' /* Constant conversion and jumps */
 [2013-09-14 06:50 UTC] krakjoe@php.net
Assuming
 [2013-09-14 06:58 UTC] krakjoe@php.net
Assuming we are just going to disable unsafe optimizations, PR #450 should do it 
???
 [2013-09-15 06:06 UTC] laruence@php.net
-Assigned To: +Assigned To: dmitry
 [2013-09-15 06:06 UTC] laruence@php.net
Hey:
   I got a different fix:

$ git diff
diff --git a/Optimizer/block_pass.c b/Optimizer/block_pass.c
index b8c3814..fd76322 100644
--- a/Optimizer/block_pass.c
+++ b/Optimizer/block_pass.c
@@ -1278,8 +1278,17 @@ static void assemble_code_blocks(zend_cfg *cfg, 
zend_op_array *op_array)
 	if (op_array->last_try_catch) {
 		int i;
 		for (i = 0; i< op_array->last_try_catch; i++) {
-			op_array->try_catch_array[i].try_op = cfg->try[i]-
>start_opline - new_opcodes;
-			op_array->try_catch_array[i].catch_op = cfg->catch[i]-
>start_opline - new_opcodes;
+			if (cfg->try[i]->access) {
+				op_array->try_catch_array[i].try_op = cfg->try[i]-
>start_opline - new_opcodes;
+			} else {
+				op_array->try_catch_array[i].try_op = 0;
+			}
+
+			if (cfg->catch[i]->access) {
+				op_array->try_catch_array[i].catch_op = cfg-
>catch[i]->start_opline - new_opcodes;
+			} else {
+				op_array->try_catch_array[i].catch_op = 0;
+			}
 		}
 		efree(cfg->try);
 		efree(cfg->catch);


dmitry, could you please verify this?

thanks
 [2013-09-16 06:42 UTC] laruence@php.net
Automatic comment on behalf of laruence
Revision: http://git.php.net/?p=php-src.git;a=commit;h=46f18ccf0d11b18c3eebdd19d4057966dfcca6fe
Log: Fixed bug #65665 (Exception not properly caught when opcache enabled)
 [2013-09-16 06:42 UTC] laruence@php.net
-Status: Assigned +Status: Closed
 [2013-11-17 09:30 UTC] laruence@php.net
Automatic comment on behalf of laruence
Revision: http://git.php.net/?p=php-src.git;a=commit;h=46f18ccf0d11b18c3eebdd19d4057966dfcca6fe
Log: Fixed bug #65665 (Exception not properly caught when opcache enabled)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 23 09:01:28 2024 UTC