php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #63206 restore_error_handler does not restore previous errors mask
Submitted: 2012-10-03 09:59 UTC Modified: 2017-12-28 18:07 UTC
Votes:20
Avg. Score:4.5 ± 0.7
Reproduced:17 of 19 (89.5%)
Same Version:2 (11.8%)
Same OS:2 (11.8%)
From: gwarnants at gmail dot com Assigned:
Status: Open Package: *General Issues
PHP Version: 5.4.7 OS: Windows XP
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: gwarnants at gmail dot com
New email:
PHP Version: OS:

 

 [2012-10-03 09:59 UTC] gwarnants at gmail dot com
Description:
------------
Dear PHP Team,

I don't know if it's a bug but I discovered a strange behavior :

When setting a custom error handler, we can choose an error mask as a 2nd parameter to catch only some kinds of errors.
If I set 2 error handlers with differents masks, and trying to restore back my first handler by calling restore_error_handler(), my first handler is now running with the second error mask

Perhaps it is a normal behavior because set_error_handler() is setting a "global" error mask, but if it is, I think there is no
way to know the previous error_mask to restore it properly (that value isn't returned by error_reporting())

Regards,
Geoffray

Test script:
---------------
class CustomErrorHandler
{
    public static function handler($errrno, $errstr)
    {
        echo "HANDLING: $errstr\n";

        // i set an internal error_handler other catch WARNINGS ONLY
        set_error_handler(array('CustomErrorHandler', 'internal_handler'), E_WARNING|E_USER_WARNING);
        fopen('file_not_found.dat', 'r');   // will trigger a E_WARNING
        restore_error_handler();    // doing this i think previous handler will be restored to E_ALL... but it's not ??
    }

    private static function internal_handler($errrno, $errstr)
    {
        echo "  INTERNAL HANDLER: $errstr\n";
    }
}


set_error_handler(array('CustomErrorHandler', 'handler'), E_ALL);

trigger_error('User notice 1',  E_USER_NOTICE);
trigger_error('User warning 1', E_USER_WARNING);
trigger_error('User notice 2',  E_USER_NOTICE); // will not be caught !
trigger_error('User warning 2', E_USER_WARNING);

Expected result:
----------------
HANDLING: User notice 1
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory
HANDLING: User warning 1
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory
HANDLING: User notice 2
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory
HANDLING: User warning 2
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory

Actual result:
--------------
HANDLING: User notice 1
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory
HANDLING: User warning 1
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory


Notice:  User notice 2 in D:\wamp\www\custom_error_handler.php on line 29

HANDLING: User warning 2
  INTERNAL HANDLER: fopen(file_not_found.dat): failed to open stream: No such file or directory

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-10-17 04:57 UTC] gwarnants at gmail dot com
Any feedback ?
 [2012-11-15 08:57 UTC] gwarnants at gmail dot com
Here is a simpler example to illustrate the problem. As you see, the 2nd trigger_error will not be caught because the error reporting isn't restored to its initial state.

set_error_handler('handler1', E_ALL);
trigger_error('notice 1',  E_USER_NOTICE); // OK
trigger_error('notice 2',  E_USER_NOTICE); // not caught !

function handler1($errrno, $errstr)
{
    echo "HANDLER1 : $errstr\n";
    set_error_handler('handler2', E_USER_WARNING);
    restore_error_handler();
}

function handler2($errrno, $errstr)
{
}
 [2013-01-02 14:14 UTC] joe dot bowman at edigitalresearch dot com
Same problem in 5.4.8 on CentOS 6.3.
 [2013-10-06 06:55 UTC] gwarnants at gmail dot com
Same problem in 5.3.4 on Windows
 [2016-01-14 02:38 UTC] hujuice at inserviblie dot org
Same here for PHP 5.6.14 on Linux
 [2016-06-03 14:06 UTC] a at ustimen dot co
Currently repeats at 5.4, 5.5 and 5.6

Seems fixed in 7.0, hhvm and nightly.

https://travis-ci.org/garex/php-error-handler-bug
 [2016-06-03 14:31 UTC] a at ustimen dot co
Sorry, my bad -- test script was not robust.

Currently it repeats at PHP from 5.2 to nightly (7.x).

Only under hhvm not repeats.

https://travis-ci.org/garex/php-error-handler-bug/builds/135038478
 [2017-12-28 18:07 UTC] nikic@php.net
Generally restore_error_handler() does restore the mask as well. What happens here is that while the error handler is called, the error handler is temporarily removed to prevent recursion. The inner set_error_handler() call then thinks that there is no error handler registered and does not save the mask.

Ideally we would not temporarily remove the error handler and instead track that it is currently running in a different way.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Oct 16 10:01:27 2019 UTC