php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #33063 Crash with complicated scoping and inheritance
Submitted: 2005-05-19 11:22 UTC Modified: 2005-05-20 10:32 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: arendjr at gmail dot com Assigned:
Status: Closed Package: Reproducible crash
PHP Version: 5.0.3 OS: Linux
Private report: No CVE-ID: None
 [2005-05-19 11:22 UTC] arendjr at gmail dot com
Description:
------------
I'm building a rather complicated framework which includes         
big inheritance trees and multiple factories operating on         
each other. I'm still using PHP 5.0.3 (with SUSE patches)     
and I'm not able to compile PHP 5.0.4 at the moment, so I     
hope I'm not reporting a problem already solved, at least   
I can't find the problem in the PHP 5.0.4 Changelog. If     
necessary, I can compile PHP 5.0.4 later do dig deeper     
into the problem.     
     
The problem is when I'm running some code using this     
framework I'm getting some nasty crashes and memory        
corruptions under certain conditions. Now my own code     
might not be perfect yet either, but with a crashing PHP        
is rather difficult to track where the problem is. I        
created 4 test cases which show the problem.        
First I have some working code which does what it should        
do. Then I try to move some code to a function so it can        
be re-used later, but suddenly PHP crashes when the code        
is in a function. Then I strip away 2 lines of code,        
causing PHP to run, but exit with a memory corruption      
reported by glibc. Finally, if I strip 3 more lines, there      
are no more problems again.   
   
Now, just while I was writing this report I think I might   
know where the problem is. My whole framework is built on  
an advanced Widget model. This has some very important  
base classes and interfaces:  
  
interface IWidget;  
class Widget extends DOMElement implements IWidget;  
class TextWidget extends DOMText implements IWidget;  
class RootWidget extends DOMDocument implements IWidget;  
class RootWidgetContainer implements IWidget;  
  
the objects which are created in the test cases are:  
  
class WebPage extends RootWidgetContainer;  
  
and under the hood (through the factories):  
  
class XHTML_RootWidget extends RootWidget;  
class XHTML_Table extends Table;  
class XHTML_TableRow extends TableRow;  
class XHTML_TableCell extends TableCell;  
class XHTML_Label extends Label;  
class XHTML_Text_Style extends XHTML_Style;  
  
where:  
  
class Table extends Widget;  
class TableRow extends Widget;  
class TableCell extends Widget;  
class Label extends TextWidget;  
class XHTML_Style extends Style;  
  
So, that's basically how the whole inheritance for this  
small example works. It's pretty complicated but allows me  
to use the same code to create all kinds of output  
documents (for example, doing a "s/WebPage/Spreadsheet/g" 
on the first testcase gives creates an OpenDocument 
Spreadsheet and sends it to the user's browser). 
 
Now, where do I think the problem is? Widget inherits 
DOMElement. And then I add new widgets to this DOMElement. 
But I do not keep references to these objects, because 
DOMElement already has the firstChild and nextSibling 
properties, so I should be able to access child widgets 
through this property. So somehow I guess the objects are 
destroyed by the garbage collector when the function in 
testcases 2 through 4 exits (even though the DOMElement 
still contain references to them). In fact, adding an 
array childWidgets to the classes Widget and RootWidget 
where I keep references to the child widgets myself 
entirely avoids the crash in all testcases. So, I think 
when a child is added to a DOMNode, the garbage collector 
should know there's a reference to the child in that node 
so it does not get destroyed too soon. 
 
If you want I can send you the other code of the 
framework, but right now I don't think throwing in a few 
thousand lines of code here would really help :) 

Reproduce code:
---------------
See the 4 testcases:

http://www.liacs.nl/~dvbeelen/php5crash/works.php
http://www.liacs.nl/~dvbeelen/php5crash/crash.php
http://www.liacs.nl/~dvbeelen/php5crash/corruption.php
http://www.liacs.nl/~dvbeelen/php5crash/works2.php

Expected result:
----------------
A Widget tree with an internal DOM tree should be built 
and shown. 

Actual result:
--------------
Using testcase 2, PHP will crash with the following  
backtrace:      
      
#0  0x081402e3 in zend_std_object_get_class_name ()      
#1  0x081570e9 in zend_init_method_call_handler ()      
#2  0x08160978 in execute ()      
#3  0x081577fc in zend_do_fcall_common_helper ()      
#4  0x08160978 in execute ()      
#5  0x08153094 in zend_include_or_eval_handler ()      
#6  0x08160978 in execute ()      
#7  0x0812c62c in zend_execute_scripts ()      
#8  0x080f54dd in php_execute_script ()      
#9  0x08161ecd in main ()     
     
With testcase 3, PHP will run, but exit with the following 
message:     
    
*** glibc detected *** double free or corruption (out):    
0x0827a260 ***    
Aborted    

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-05-19 12:31 UTC] derick@php.net
Thank you for this bug report. To properly diagnose the problem, we
need a short but complete example script to be able to reproduce
this bug ourselves. 

A proper reproducing script starts with <?php and ends with ?>,
is max. 10-20 lines long and does not require any external 
resources such as databases, etc.

If possible, make the script source available online and provide
an URL to it here. Try to avoid embedding huge scripts into the report.

we miss your WebPage class include file
 [2005-05-19 14:27 UTC] arendjr at gmail dot com
Okay, but beware that including WebPage.php will include a total of 10 files. I created a simple tarball which you can untar, enter the directory and run 'php5 index.php'. I stripped as much as I could while still letting my code function. I left the API docs in as it might help you to understand the code better ;)
The most important file is base/Widgets.php. If you replace it with base/Widgets.php.safe, the crash will no longer occur as it contains a workaround by explicitly holding references to child widgets.
index.php contains the first testcase plus a set_include_path() to get everything to work.
You can download the tarball from www.liacs.nl/~dvbeelen/php5crash/aukyla2-bugreport.tar.gz
 [2005-05-19 16:14 UTC] derick@php.net
Then you need to try a bit harder creating a shorter reproducable script.... really.
 [2005-05-20 09:20 UTC] arendjr at gmail dot com
Okay, it took some effort, by I created 3 new test cases. The longest one, the one with the crash, is 47 lines (including whitespace) and has no includes. I got also two workarounds, the first removes the unused references to $rootWidget after which the problem disappears. The second one again no longer uses a function to populate the document, after which it works again. I hope this helps.
http://www.liacs.nl/~dvbeelen/php5crash/crash.php.txt
http://www.liacs.nl/~dvbeelen/php5crash/crash-workaround1.php.txt
http://www.liacs.nl/~dvbeelen/php5crash/crash-workaround2.php.txt
 [2005-05-20 10:32 UTC] arendjr at gmail dot com
Darn, I just installed PHP 5.0.4 which appears to have solved the problem already. Nevermind...
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Tue Jul 15 14:01:33 2025 UTC