php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #20070 PHPDoc unrestrained recursion seg. faults php
Submitted: 2002-10-24 13:39 UTC Modified: 2002-10-28 16:46 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: mattb at columbia dot edu Assigned:
Status: Closed Package: PEAR related
PHP Version: 4.2.3 OS: GNU/Linux 2.4.18-17.7.x (RedHat)
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
MUST BE VALID
Solve the problem:
28 + 41 = ?
Subscribe to this entry?

 
 [2002-10-24 13:39 UTC] mattb at columbia dot edu
I've created a class whose comments seems to cause PHP to seg. fault when running PHPDoc. I've attached the file which causes the seg. fault as well as the output from "php -i". Here are the PEAR files I have installed:

% pear list-installed
Installed packages:
===================
+---------+---------+--------+
| Package | Version | State  |
| PHPDoc  | 0.1.0   | beta   |
| PHPUnit | 0.4     | stable |
+---------+---------+--------+

Here is the command I use to run phpdoc:

% ls -a ~/php
.  ..  Base.php
% rm -fr /tmp/phpdoc ; phpdoc -s ~/php -d /tmp/phpdoc \
  -t $PHP_HOME/share/pear/PHPDoc
zsh: segmentation fault  phpdoc ...

I don't have debugging symbols compiled into my version of PHP, but GDB shows would looks like unrestrained recursion happening:

  (no debugging symbols found)...
  Program received signal SIGSEGV, Segmentation fault.
  [Switching to Thread 1024 (LWP 1114)]
  0x080b06ef in ?? ()
  (gdb) bt
  #0  0x080b06ef in ?? ()
  #1  0x080af0cc in ?? ()
  #2  0x080af9e1 in ?? ()
  #3  0x080af0cc in ?? ()
  #4  0x080af9e1 in ?? ()
  #5  0x080af0cc in ?? ()
  #6  0x080af9e1 in ?? ()
  #7  0x080af0cc in ?? ()
  #8  0x080af9e1 in ?? ()
  #9  0x080af0cc in ?? ()
  #10 0x080af9e1 in ?? ()
  #11 0x080af0cc in ?? ()
  #12 0x080af9e1 in ?? ()
  ...
  #8513 0x080af0cc in ?? ()
  #8514 0x080af9e1 in ?? ()
  #8515 0x080af0cc in ?? ()
  #8516 0x080af9e1 in ?? ()
  #8517 0x080af0cc in ?? ()
  #8518 0x080af008 in ?? ()
  #8519 0x080af008 in ?? ()
  #8520 0x080b1903 in ?? ()
  #8521 0x080b1903 in ?? ()
  #8522 0x080b1903 in ?? ()
  #8523 0x080af0cc in ?? ()
  #8524 0x080b1f74 in ?? ()
  #8525 0x080a77a6 in ?? ()
  #8526 0x080a7b6c in ?? ()
  #8527 0x0815710b in ?? ()
  #8528 0x081572df in ?? ()
  #8529 0x081572df in ?? ()
  #8530 0x081572df in ?? ()
  #8531 0x081572df in ?? ()
  #8532 0x0812ddee in ?? ()
  #8533 0x08067fb2 in ?? ()
  #8534 0x08065574 in ?? ()
  #8535 0x404ae1c4 in __libc_start_main () from /lib/libc.so.6

I'll try and paste the file here, but feel free to e-mail me for the actual file (and the output from strace):

<?php

// Protected global constants

//========================================================================
/**
 * the prefix of all vars which hold field values
 * @const _ARENA_DATA_BASE_FIELD_PREFIX
 */
define('_ARENA_DATA_BASE_FIELD_PREFIX', '__field_');

//========================================================================
/**
 * the string length of _ARENA_DATA_BASE_FIELD_PREFIX
 * @const _ARENA_DATA_BASE_FIELD_PREFIX_LEN
 */
define('_ARENA_DATA_BASE_FIELD_PREFIX_LEN', strlen(_ARENA_DATA_BASE_FIELD_PREFIX));

//========================================================================
/**
 * Base class to represent a row in a table.
 *
 * Copyright (c) 2002 <a href="http://arenaunlimited.com/">Arena
 * Unlimited, Inc.</a> All rights reserved.
 *
 * Reproduction, distribution, use, and/or modification of this software
 * is strictly prohibitted without express written consent from Arena
 * Unlimited, Inc.
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @author Matthew Bogosian <matt@arenaunlimited.com>
 * @package arena::data
 * @version $Id: Arena_Base.php,v 1.1 2002/10/08 07:37:14 matt Exp $
 */
class Arena_Data_Base
{

    // Constructor

//========================================================================
/**
 * Class constructor.
 *
 * @param PEAR_DB &$a_Connection the PEAR_DB connection object
 * @access public
 */
    function Arena_Data_Base(&$a_Connection)
    {
        $__connection = &$a_Connection;
    }

    // Public methods

//========================================================================
/**
 * Returns the PEAR_DB connection associated with this database object.
 *
 * @return object PEAR_DB the connection associated with this database
 * object
 * @access public
 */
    function &getConnection()
    {
        return $__connection;
    }

    // Protected hook methods

//========================================================================
/**
 * Returns the names of the fields associated with this database object.
 * This hook function may be overridden by subclasses. However, there is
 * no need for subclasses to override this function if the subclass has a
 * declared var for each of its corresponding table fields named:
 * <code>
 *   _ARENA_DATA_BASE_FIELD_PREFIX . [FIELD_NAME]
 * </code>
 * (Where [FIELD_NAME] is the name of the field.) Since vars are more
 * strict than variable declarations, this must be done by declaring vars
 * with fixed names in the subclass in the following manner:
 * <code>
 *   var $__field_[FIELD_NAME];
 * </code>
 * Note: in versions up to and including PHP4, the following will not
 * work:
 * <code>
 *   // Not allowed by PHP
 *   var ${_ARENA_DATA_BASE_FIELD_PREFIX . [FIELD_NAME]};
 * </code>
 * Here's an example for three fields named, 'id', 'full_name' and
 * 'has_the_clap':
 * <code>
 *   var $__field_id;
 *   var $__field_full_name;
 *   var $__field_has_the_clap;
 * </code>
 * Alternatively, if you're all right with losing some introspection
 * functionality on your subclasses, you can get rid of the var
 * declarations altogether and do something like the following in your
 * constructor:
 * <code>
 *   $this->{_ARENA_DATA_BASE_FIELD_PREFIX . [FIELD_NAME]} = null;
 * </code>
 * This will allow you to use the constant notation without hard-coding
 * '__field_' everywhere. This function uses instance inspection to build
 * the list of field names so even a combination of both techniques is
 * acceptable. However, keep in mind that if it's not a var, and you unset
 * it, this function will lose visibility into it:
 * <code>
 *   // This may have side effects; set it to null instead
 *   unset($this->{_ARENA_DATA_BASE_FIELD_PREFIX . [FIELD_NAME]});
 * </code>
 * The array that is returned from the function is an array of the
 * following format:
 * <code>
 *   array
 *   (
 *       [FIELD_NAME] => [FIELD_NAME], ...
 *   );
 * </code>
 * Note that the field name is both the key and the value. This is
 * intended to enable maximum flexibility by easing the complexity of
 * subclasses that wish to extend this method while retaining the ability
 * to use the resulting array in a foreach loop:
 * <code>
 *   class SubClass extends Arena_Data_Base
 *   {
 *       ...
 *       function &_getFieldNames()
 *       {
 *           $myFieldNames = array(...);
 *           return array_merge(parent::_getFieldNames(), $myFieldNames);
 *       }
 *   }
 *   ...
 *   foreach ($mySubClass->_getFieldNames() as $fieldName) {...}
 * </code>
 * In order for this to work, all subclasses must also follow the
 * [FIELD_NAME] => [FIELD_NAME] convention.
 *
 * @return array the names of the fields associated with this database
 * object
 * @access protected
 */
    function &_getFieldNames()
    {
        // Get the instance variables
        $varNames = array_keys((array)($this));
        $fieldNames = array();

        // Figure out which names match
        foreach ($varNames as $varName)
        {
            if (strncasecmp(_ARENA_DATA_BASE_FIELD_PREFIX, $varName, _ARENA_DATA_BASE_FIELD_PREFIX_LEN) == 0
                && strlen($varName) > _ARENA_DATA_BASE_FIELD_PREFIX_LEN)
            {
                $fieldName = substr($varName, _ARENA_DATA_BASE_FIELD_PREFIX_LEN);
                $fieldNames[$fieldName] = $fieldName;
            }
        }

        return $fieldNames;
    }

//========================================================================
/**
 * Returns the table name associated with this database object.
 *
 * @return string the table name associated with this database object
 * @access protected
 */
    function &_getTableName()
    {
        return '';
    }

//========================================================================
/**
 * Returns the field names which make up the primary key of this database
 * object. The return from this function has the same format as
 * Arena_Data_Base::_getFieldNames().
 *
 * @return array the field names which make up the primary key of this
 * database object
 * @access protected
 * @see Arena_Data_Base::_getFieldNames()
 */
    function &_getPrimaryKey()
    {
        return _getFieldNames();
    }

    // Private data members

//========================================================================
/**
 * the database connection
 *
 * @var object PEAR_DB
 * @access private
 */
    var $__connection;

}

?>

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-10-28 10:49 UTC] iliaa@php.net
Unrestrained resucrsion such as:
function a() { a(); } a(); will always core until PHP implements it's own stack, which is unlikely to ever happen. Therefor, you should either, not use recursive functions or harcode some sort of a recurssion limit if you are not certain about the maximum possible number of recursions.
 [2002-10-28 12:11 UTC] mattb at columbia dot edu
> Unrestrained resucrsion such as:
> function a() { a(); } a(); will always core until PHP implements it's
> own stack, which is unlikely to ever happen. Therefor, you should
> either, not use recursive functions or harcode some sort of a
> recurssion limit if you are not certain about the maximum possible
> number of recursions.

HUH?! phpdoc is calling one of its own functions recursively! How can I possibly be responsible for avoiding recursion and stack allocation when I'll i'm doing is running phpdoc on an input file to generate documentation?

I even provided the file that was causing it to do this in my bug report. Did you even read it before marking it as "Won't fix"? I went through a lot  of effort to provide as much detail as I could to make it as easy as possible to reproduce the problem and fix it. Did you even try?

Unrestrained recursion is a bug. Period. There's no valid outcome regardless of the architecture to deal with it (PHP's own stack or not).

phpdoc is an incredibly buggy tool, and it is VERY delicate. How can anyone expect it to become a standard in its current state if its bugs are written off without any investigation?
 [2002-10-28 16:46 UTC] timmyg@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

This is expected behavior.  Read the docs, do not mix procedural code with classes.  the file processes just fine when the defines are removed, or the class is removed.  try it.  The only work-around I have for this, is to put the defines after the class, but this (according to the docs) is not supported behavior.
 
PHP Copyright © 2001-2021 The PHP Group
All rights reserved.
Last updated: Sun Nov 28 00:03:13 2021 UTC