php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #50380 non static class calls inside of objects will cause a fake __call and crashes
Submitted: 2009-12-04 09:11 UTC Modified: 2010-10-17 17:48 UTC
From: dkr at mindwerk dot de Assigned: felipe (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.2.11 OS: linux 2.6.21
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: dkr at mindwerk dot de
New email:
PHP Version: OS:

 

 [2009-12-04 09:11 UTC] dkr at mindwerk dot de
Description:
------------
I don't really understand the following situation.. Made some comments in the code to explain it. There is something wrong with class and Object scopes: calling a non-static function of another class inside an object will cause __call (in dependence of existence in the other class) to different behaviors when using self:: instead of __CLASS__ in the non-static method.


Reproduce code:
---------------
<?php
class Foo
{
	function __call($f,$a)
	{
		die("__called!\n");
	}
	function write($text) {
		echo($text);
	}
	// defining debug as static will cause
	// the whole thing to work properly
	function debug($text) {
		return call_user_func_array(
			// "self" acts like making a lookup in
			// class Bar, fails and then runs the
			// magic method in this class, but why?
			// i dont have extended the Bar class...
			// __CLASS__ will work, but dont work for
			// extended classes, as self should do it
			array(self,'write'),
			array($text,1)
		);
	}
}

class Bar {
	function __construct()
	{
		Foo::debug("foobar\n");
	}
	
	// uncomment the following to make Foo::debug()
	// throw the text foobar, ehm? note that we do NOT
	// echo any content here... that is something like
	// inheritance it should not do? will echo "foobar"..
	
	/*
	function __call($f,$a)
	{
	}
	*/
}

$bar = new Bar(); // will cause php to die


Expected result:
----------------
foobar

Actual result:
--------------
__called!

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-12-04 09:23 UTC] jani@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

If you comment out the __call magic you'll get pretty clear error message why and what goes wrong.
 [2009-12-04 19:02 UTC] dkr at mindwerk dot de
If i uncomment Bar::__call, i get the text "foobar" and not "__called!" or any other error. That is how 5.2.11 (not tried another version) handles it here currently.. I will try others later.

So, if self:: does rely on the scope of the object we came from (because we have NOT defined the function as static), Foo::__call should never be called if self:: or $this is used in Foo, or am i wrong?

It is something like PHP uses Bar::__call if it exists and if not Foo::__call(), hence we are not extending the class...

Output if Bar::__call commented: "foobar"
Output if Bar::__call uncommented: "__called!"
 [2009-12-08 16:33 UTC] dkr at mindwerk dot de
No, that is NOT BOGUS i think, there is something went wrong, and it took me quite a while finding the error in the app (using strace etc), and quite a while yet to reproduce this behavior with a small code snippet that will SEGFAULT. 

Note: Currently only tested on 5.2.11 and 5.2.0-8+etch15

Reproduce code:
---------------

<?php
class Foo
{
	function __call($f,$a)
	{
		echo("__call activated on class: ".__CLASS__.PHP_EOL);
	}
	function write($text) {
		echo( 'Foo: '.$text.PHP_EOL );
	}
	function debug($text) {
		return call_user_func_array(
			array(self,'write'),
			array($text,1)
		);
	}
}

class Bar {
	function __construct()
	{
		Foo::debug("foobar");
	}
}

class Baz {
	function __construct()
	{
		Foo::debug("foobar");
	}
	// here he dies...
	function __call($f,$a)
	{
		echo("__call activated on class: ".__CLASS__.PHP_EOL);
	}
}

$bar = new Bar();
$baz = new Baz(); // will cause php to die
?>

Expected result:
----------------
1. Calling non-static function Foo::debug() in Bar::__construct() 
a) should throw an function not found error while "self::" is used, as the engine does a lookup in Bar and does not find any function.
b) should not make the usage of Foo::__call() as it does not interact in the scope of Class Foo finally?

2. Calling Foo::debug() in Baz::__construct() in Baz::__construct()
a) should use __call as it is defined in Baz, and should rely on the scope of this class and not the non static called class Foo.. Uncomment Foo::__call to let the whole thing get more weird, as the text "Baz::foobar" is normally echoed if Baz::__call is only defined there (only defined!)
b) should never make the usage of Foo::call() as it does not interact in the scope of Class Foo finally?

Actual result:
--------------
dkr@*:~$ php test.php
__call activated on class: Foo
Segmentation fault
dkr@*:~$

Actual result without Foo::__call():
------------------------------------
dkr@*:~$ php phptest.php
PHP Warning:  call_user_func_array(): Unable to call self::write() in * on line *
Foo: foobar
dkr@*:~$
 [2009-12-08 16:59 UTC] felipe@php.net
__call activated on class: Foo

Warning: String is not zero-terminated (ZZZZZZ&#65533;&#65533;&#65533;) (source: /home/felipe/dev/php5_2/Zend/zend_execute_API.c:414) in /home/felipe/dev/bug.php on line 15
[Tue Dec  8 14:59:22 2009]  Script:  '../bug.php'
---------------------------------------
/home/felipe/dev/php5_2/Zend/zend_execute_API.c(414) : Block 0x08b757f0 status:
/home/felipe/dev/php5_2/Zend/zend_variables.c(35) : Actual location (location was relayed)
Beginning:  	Cached
Freed (invalid)
    Start:	OK
      End:	OK
---------------------------------------
Foo: foobar
[Tue Dec  8 14:59:22 2009]  Script:  '../bug.php'
/home/felipe/dev/php5_2/Zend/zend_object_handlers.c(767) :  Freeing 0x08B75B80 (44 bytes), script=../bug.php
[Tue Dec  8 14:59:22 2009]  Script:  '../bug.php'
/home/felipe/dev/php5_2/Zend/zend_object_handlers.c(775) :  Freeing 0x08B75E7C (6 bytes), script=../bug.php
=== Total 2 memory leaks detected ===

 [2009-12-14 14:48 UTC] dkr at mindwerk dot de
Hm, i just think that this is an endless loop that should throw any error like "max function nesting reached" or something. The following codes are 2 easier examples that will fault:

Reproduce code #1:
------------------
<?php
class Foo {
	static function __call($f,$a) {
		static $call = 0;
		test();
	}
}
function test() {
	call_user_func_array(array('Foo','__call'),array(0,array()));
}
test();
?>

Reproduce code #2:
------------------
<?php
function Bar() {
	Foo();
}
function Foo() {
	Bar();
}
Foo();
?>

Expected result:
----------------
Fatal Error: Maximum calls of nested functions reached in ... on line ...

Actual result:
--------------
Segmentation fault
 [2010-01-11 08:53 UTC] David dot Gausmann at measx dot com
On Windows XP SP3 I've got the following output (I've switched error reporting to E_ALL):
Notice: Use of undefined constant self - assumed 'self' in C:\xampp\htdocs\test3.php on line 49
foobar
 [2010-10-17 17:48 UTC] felipe@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: felipe
 [2010-10-17 17:48 UTC] felipe@php.net
It looks already fixed.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Mon Aug 11 17:00:03 2025 UTC