Bug #17683 Updated: Reference counting broken - dummy assignments needed to maintain a reference
| From: | duncan at emarketeers dot com | Date: | Mon, 10 Jun 2002 16:18:52 +0000 |
| Subject: | Bug #17683 Updated: Reference counting broken - dummy assignments needed to maintain a reference | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-10028@lists.php.net to get a copy of this message | ||
ID: 17683
Updated by: duncan@emarketeers.com
Reported By: duncan@emarketeers.com
-Status: Feedback
+Status: Open
Bug Type: Scripting Engine problem
Operating System: Various Linuxes
PHP Version: 4.2.1
New Comment:
I can't get 4.3 to compile properly:
there's a bug in sapi/apache/php_apache.c at
line 186. I removed the ifdefs to make it
compile, which it seems to do. But then make
install segfaults during the PEAR
installation. It does copy the php module
across to the apache src dir though, and it
builds OK but segfaults on startup.
Previous Comments:
------------------------------------------------------------------------
[2002-06-10 11:44:55] mfischer@php.net
This looks like something which _might_ have been addressed in Zend
Engine 2. Can you try it with PHP4.3.0-dev/ZE2 ?
http://www.php.net/distributions/php-4.3.0-dev-zend2-alpha1.tar.gz
for
the tarball, please see the php.net itself for the announcement,
examples and README's.
------------------------------------------------------------------------
[2002-06-10 11:33:18] duncan@emarketeers.com
Under some circumstances PHP seems to lose track of the number of
references it has to a variable (at least, that is what I think is
happening).
In the following script, look for the line "/** remove the following
line and things break **/" in TelesInvoiceParser::_endElement().
The critical lines are:
$this->currentElement =& $this->currentElement->parent;
which fails, and:
$p =& $this->currentElement->parent;
$this->currentElement =& $this->currentElement->parent;
which works. It appears that the dummy reference $p is needed for the
parent property to continue to exist out of the scope of the method.
======== Explanation of script ================
What is happening is that as an XML document is parsed, every time a
new element is found a matching object is created and set to be the new
"currentElement" and this new currentElement's "parent" property is set
to a reference to the previous currentElement. In this way when the
element is closed we can get back to its enclosing element.
============= PHP configure flags ==============
./configure --with-apache=../apache_1.3.19/ --with-mysql
--with-xslt-sablot --enable-xslt --with-expat-dir=/usr
The input XML is
======== XML ===========
<invoice>
<from>
<date day="15" month="12" year="2001"/>
</from>
<to>
<date day="14" month="12" year="2001"/>
</to>
<issuer>1</issuer>
<person id="1234">
<order>4567</order>
<traffic no="0" rate="0" zone="2">24</traffic>
<traffic no="1" rate="4" zone="2">48</traffic>
<traffic no="2" rate="6" zone="2">96</traffic>
<traffic no="3" rate="8" zone="2">37</traffic>
</person>
</invoice>
========== END XML ==============
========== PHP ===================
<?
////
// Class to parse a Xc Invoice XML Document
////
class XcXMLElement {
var $parent = null;
var $cdata = "";
function setA($attributes) {
global $indent;
$indent.=" ";
echo "<p>$indent Setting up a new ".get_class($this)."</p>\n";
foreach($attributes as $name => $value) {
$this->$name = $value;
}
}
function setD($cdata) {
$this->cdata .= $cdata;
}
function end() {
global $indent;
echo "<p>$indent end of element ".get_class($this)."</p>\n";
$indent = substr($indent,0,strlen($indent) - 14);
}
}
class XcInvoice extends XcXMLElement {
var $from, $to, $issuer, $person=array();
function end() {
$this->parent->invoice =& $this;
parent::end();
}
}
class XcFrom extends XcXMLElement {
var $date;
function end() {
$this->parent->from =& $this;
parent::end();
}
}
class XcTo extends XcXMLElement {
var $date;
function end() {
$this->parent->to =& $this;
parent::end();
}
}
class XcDate extends XcXMLElement {
var $day, $month, $year;
function timestamp() {
return
$this->year.$this->leading($this->month,2).$this->leading($this->day,2)."000000";
}
function leading($value,$length) {
////
// Make sure there are the right number of leading zeros on a number
////
$num = "0000$value";
return substr($value,-$length);
}
function end() {
$this->parent->date =& $this;
parent::end();
}
}
class XcPerson extends XcXMLElement {
var $id;
var $order;
var $traffic = array();
function end() {
////
// When a complete person object has been read, we write its data to
the database
////
global $indent;
echo "$indent Writing a person to the database<br>";
echo "$indent Data for the period
".$this->parent->from->date->timestamp()." to
".$this->parent->to->date->timestamp()."<br>\n";
parent::end();
}
}
class XcOrder extends XcXMLElement { }
class XcIssuer extends XcXMLElement { }
class XcTraffic extends XcXMLElement {
var $no, $rate, $zone;
var $class="XcTraffic";
}
$indent="";
class XcInvoiceParser {
var $fp;
var $invoice; // Invoice currently being constructed
var $fromDate;
var $toDate;
var $xmlParser;
function XcInvoiceParser($filename) {
$this->elementHandlers = array(
"invoice" => new XcInvoice,
"from" => new XcFrom,
"to" => new XcTo,
"date" => new XcDate,
"issuer" => new XcIssuer,
"person" => new XcPerson,
"order" => new XcOrder,
"traffic" => new XcTraffic
);
$this->fp = fopen($filename,"r");
$this->state = null;
$this->invoice = null;
$this->fromDate = null;
$this->toDate = null;
$this->issuer = null;
$this->xmlParser = xml_parser_create();
xml_set_object($this->xmlParser, &$this);
xml_set_element_handler($this->xmlParser,"startElement","endElement");
xml_set_character_data_handler($this->xmlParser, "cdata");
xml_parser_set_option($this->xmlParser,XML_OPTION_CASE_FOLDING,false);
$this->level = 0;
}
function startElement($parser,$element,$attributes) {
$this->level++;
echo "start element $element at level $this->level <br>\n"; flush();
if($handler = $this->elementHandlers[$element]) {
$handler->parent =& $this->currentElement;
$this->currentElement =& $handler;
$this->currentElement->setA($attributes);
} else {
echo "Unknown element $element";
exit;
}
}
function endElement($parser,$element) {
$this->_endElement($parser, $element);
echo "Ended OK"; flush();
}
function _endElement($parser,$element) {
echo "ending element $element at level $this->level .."; flush();
$this->currentElement->end();
$this->level--;
if(!$this->currentElement->parent) {
echo "Oops!! ";
exit;
}
echo "popping up the stack from ".get_class($this->currentElement)."
to ".get_class($this->currentElement->parent)."..<br>\n";
flush();
/** remove the following line and things break!! **/
$p =& $this->currentElement->parent;
$this->currentElement =& $this->currentElement->parent;
echo "popped<br>\n"; flush();
echo "currentElement is now
".get_class($this->currentElement)."<br>\n";
flush();
}
function cdata($parser,$cdata) {
if(!$this->currentElement) {
echo "Can't set CDATA on a null element<br>\n";
flush();
exit;
}
$this->currentElement->setD($cdata);
}
function parse() {
while($line = fread($this->fp,4096)) {
if(!xml_parse($this->xmlParser, $line, feof($this->fp))) {
echo "ERROR READING FILE";
exit;
}
}
}
}
$p = new XcInvoiceParser("/tmp/toto");
$p->parse();
?>
===================== END PHP ========================
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=17683&edit=1