Bug #17683 Updated: Reference counting broken - dummy assignments needed to maintain a reference

From: Date: Mon, 10 Jun 2002 19:12:03 +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-10033@lists.php.net to get a copy of this message
ID: 17683 Updated by: sniper@php.net Reported By: duncan@emarketeers.com -Status: Open +Status: Feedback Bug Type: Scripting Engine problem Operating System: Various Linuxes PHP Version: 4.2.1 New Comment: What exactly was the compile error you got? Previous Comments: ------------------------------------------------------------------------ [2002-06-10 12:18:51] duncan@emarketeers.com 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. ------------------------------------------------------------------------ [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.="&nbsp; &nbsp; "; 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

« previous php.bugs (#10033) next »