php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #23619 set_error_handler registered hdler not called for object instances
Submitted: 2003-05-13 21:26 UTC Modified: 2003-05-21 16:44 UTC
From: ldemailly at qualys dot com Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: 4CVS-2003-05-13 (stable) OS: Linux 2.4.20
Private report: No CVE-ID:
 [2003-05-13 21:26 UTC] ldemailly at qualys dot com
set_error_handler registered not called:
very nasty/triky bug to nail/reproduce:

I'm now at the point where if I try to minimize
further the test scripts, the bug goes away:
for instance, removing the "require q.inc" where
q.inc is an empty file, or changing code that
is *after* the offending code makes the bug go
away (hides it), so I suspect some nasty problem
in the engine, because it seems memory usage and/or
complexity of the script to be parsed affects the outcome.

to repro: copy paste, uudecode; gtar xvfz test_err.tgz
cd test_err; php ErrorBug.php
it will output "INSIDE test_should_error_out()"
but not "ERROR HANDLER CALLED" as it should if
you look at PHPUnit/TestCase.php line 158 and 147

the error is raised (as the Notice: Undefined variable:  foo in /home/dl/dev/cvs/qualys/web/dev/current/internal/test_err/ErrorBug.php on line 7 demonstrates) but the handler is not called...

if you edit BugTest1.php to remove the require 'q.inc' for
instance, you will now see "ERROR HANDLER CALLED"
even though q.inc is empty and should thus make no difference at all !

ps: the code has been modified from pear's phpunit module with a submitted patch for error handling; which works 'sometimes' (most of the time actually). in the tgz below, I removed a lot of stuff to make the files as small as possible... (incl headers/copyright notices, etc...))

I spent many many hours trying to narrow it down further
(having a simpler script) but didn't manage, sorry for
having a large set of files needed ...

This is with the latest cvs (2003-05-13) on redhat linux 9

next message will be the .uu, if you're having any
trouble, please email and I'll (re)send the repro scripts


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2003-05-14 10:42 UTC] sniper@php.net
You're propably doing something wrong. As long as you can't provide a _SHORT_ example script which clearly shows the problem, we'll assume that.

 [2003-05-14 14:01 UTC] ldemailly at qualys dot com
Aha, I managed to reduce the repro script dramatically :

<?php
ini_set("error_reporting" , E_ALL);

class TestErrorHdl {
    // Will not be called !!
    function errorHandler($errno, $errstr, $errfile, $errline) {
        echo("ERROR HANDLER CALLED (EXPECTED)\n");
    }
    function runTest() {
        $res = set_error_handler(array(&$this, "errorHandler"));
	echo("set_error_handler done retcode=" . $res . "\n");
        $bar = $foo;
    }
}

$t = new TestErrorHdl();
$t->runTest();

?>

--- output (buggy, with current 4.3 php cli versions): ----
$ php ErrorBug.php
set_error_handler done retcode=1
 
Notice: Undefined variable:  foo in /home/dl/test_err_tiny/ErrorBug.php on line
12
--- output (expected) : ----
set_error_handler done retcode=1
ERROR HANDLER CALLED (EXPECTED)


[note that with a longer script it does *most of the time*
work as expected, so it's not like the feature of
having an instance method for a error handler is not
supported at all...]
 [2003-05-14 16:18 UTC] ldemailly at qualys dot com
A collegue of mine (Thanks Walter!) here actually found 
a fix (patch below);
looking at the code it is puzzling that it would
ever work, there seems to be some other bug/corruption
in the zend engine that would explain why it works/
behave differently sometimes. Also that test for empty
string should probably be before the test for callable... ?

php-4.3.1-walt/Zend/zend_builtin_functions.c 
--- php-4.3.1/Zend/zend_builtin_functions.c     2002-11-27
12:11:10.000000000 -0800 
+++ php-4.3.1-walt/Zend/zend_builtin_functions.c        2003-05-14
13:15:39.000000000 -0700 
@@ -891,7 +891,8 @@ 
       } 
       ALLOC_ZVAL(EG(user_error_handler)); 

-       if (Z_STRLEN_PP(error_handler)==0) { /* unset user-defined
handler */ 
+    /* Make sure we test for an empty string on a non-array value here
*/ 
+       if (Z_TYPE_PP(error_handler) == IS_STRING &&
Z_STRLEN_PP(error_handler)==0) { /* unset user-defined handler */ 
               FREE_ZVAL(EG(user_error_handler)); 
               EG(user_error_handler) = NULL; 
               RETURN_TRUE;
 [2003-05-15 12:06 UTC] sniper@php.net
Seems to work fine with current stable CVS.
(without the patch, which is bogus anyway.)

 [2003-05-15 13:18 UTC] wboring at qualys dot com
I tested this with php 4.3.1 and found that the code assumes that what is passed in to set_error_handler() is a string, which you can clearly see by the line
...
if (Z_STRLEN_PP(error_handler)==0) { /* unset user-defined
...

This is wrong and does not work when you pass an array into set_error_handler( array(&$this, "myhandler") );

error_handler is an array zval, and therefore the test for Z_STRLEN_PP always returns 0.  This case falls through and sets the user_error_handler = NULL;
which prevents the user defined handler from working at all.  I am able to reproduce this 100% of the time.  Please fix this, as it is totally broken in its current state.  The patch provided works.  

  Also, if you assume that the variable passed in is a string, and happens to be empty, then why do we RETURN_TRUE; in that block, when in fact the user_error_handler is NOT set, and is set to NULL.  This is also wrong.  This is an error case which should return FALSE.
 [2003-05-15 14:03 UTC] ldemailly at qualys dot com
sniper, what did you try exactly ?
I tried again with the latest from cvs and

./configure  --with-oci8=$ORACLE_HOME \
             --with-apache=../../apache_1.3.27 --with-mcrypt=/usr/local \
             --enable-sysvsem --enable-sysvshm --enable-trackvars \
             --with-gd --with-png-dir=/usr \
             --with-jpeg-dir=/usr --with-zlib-dir=/usr \
             --with-mysql=/usr

and from the command line :
[dl@dl-pc php4]$ sapi/cli/php ~/foo.php
set_error_handler done retcode=1
 
Notice: Undefined variable:  foo in /home/dl/foo.php on line 12

This is another patch, as that unset thing seems
to leave stuff corrupt and looks like dead code
anyway (is_callable would theoritically fail for
an empty string anyway)

*** zend_builtin_functions.c.~1.124.2.4.~	2002-12-31 08:22:58.000000000 -0800
--- zend_builtin_functions.c	2003-05-15 12:01:48.000000000 -0700
***************
*** 891,902 ****
  	}
  	ALLOC_ZVAL(EG(user_error_handler));
  
- 	if (Z_STRLEN_PP(error_handler)==0) { /* unset user-defined handler */
- 		FREE_ZVAL(EG(user_error_handler));
- 		EG(user_error_handler) = NULL;
- 		RETURN_TRUE;
- 	}
- 
  	*EG(user_error_handler) = **error_handler;
  	zval_copy_ctor(EG(user_error_handler));
  
--- 891,896 ----

with the patch :
[dl@dl-pc php4]$ sapi/cli/php ~/foo.php
set_error_handler done retcode=
ERROR HANDLER CALLED (EXPECTED)
 [2003-05-15 18:32 UTC] sniper@php.net
That patch is also bogus.
And as I said already: It works fine with latest _stable_ CVS. check what php -v outputs, it's propably not the same version I'm trying this with.

 [2003-05-15 18:41 UTC] sniper@php.net
You should try this package:
 
 http://downloads.php.net/jani/php-4.3.2RC3.tar.gz

And DO NOT run buildconf for it!!

 [2003-05-15 19:02 UTC] waboring at qualys dot com
The patch is NOT bogus.  As I clearly explained earlier in the most plain english I can say, that test tests for a STRING.  It is NOT a string.  it is an ARRAY.  It will fall through 100% of the time.  This has to be fixed.  The code is totally broken.
 [2003-05-15 19:30 UTC] ldemailly at qualys dot com
Did you actually TRY ? I did (again) :

[dl@dl-pc php-4.3.2RC3]$ ./configure && make && sapi/cli/php ~/foo.php
...build output...

Build complete.
(It is safe to ignore warnings about tmpnam).
 
set_error_handler done retcode=1
 
Notice: Undefined variable:  foo in /home/dl/foo.php on line 12

which is NOT WORKING
(given that the code hasn't changed and still remove
the handler when the string length is 0, it is not
surprising it does not work... did you actually even
glanced at the code and patch ??)

PLEASE actually TRY the command line above (after saving
the repro script above into foo.php)

PLEASE try to explain (to yourself and to me) what 
happens in that if (Z_STRLEN_PP(error_handler)==0) 
when error_handler is an array like in the test script...
(for bonus points: find what other bug/corruption cause
that code to actually work in some cases...)

If it works for you, you have the lucky other corruption/
bug that make it work *sometimes*; 
What OS/configuration exactly do you use if you 
do see "ERROR HANDLER CALLED (EXPECTED)" ?
I use redhat linux 9.0 (same on 7.2 actually)
 [2003-05-15 20:10 UTC] sniper@php.net
Okay, I'm getting the same output now as you do,
when I configured a plain PHP (with only --disable-all).

And it seems your last patch is not bogus after all. :)
Now I need to figure out why it DID work for me even
without your patch..


 [2003-05-15 20:57 UTC] ldemailly at qualys dot com
Ah, Thanks !

yes, I have a larger script, doing basically
the same which "works" even in a fully configured
php (and also I think even the small one might work
when using the apache module instead of the cli), 
while looking at the code it shouldn't ever work
(the only way it would is that there is
another bug which corrupts somehow the structure
to make the string length of the array be != 0
or something else very weird... (as again, changing
unrelated code elsewhere would change the output...))

so I suggest that :
a) we fix the error handler for the next release
(by removing the whole if, assuming that wouldn't
cause regressions for people expecting set_error_handler ""
to unset handlers (they should use restore_handler ?))
we should also have a return at the end of the function
instead of falling through (the doc I think claims
it returns the previous handler, I don't think it does?)

b) keep the broken version around to get to the root
cause / find the other bug, probably nasty, which
make it work with some other config/script lengths,...

my 2 cents
thx
 [2003-05-21 16:44 UTC] sniper@php.net
Fixed in CVS. I left the part there, just commented it out for now so we don't forget about the issue.

 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Thu Apr 17 18:02:13 2014 UTC