ID:               22510
 User updated by:  php at codewhore dot org
 Reported By:      php at codewhore dot org
 Status:           Verified
 Bug Type:         Scripting Engine problem
 Operating System: Linux 2.4
 PHP Version:      4.3.2-RC1
 New Comment:

Hi:

I believe there's a missing refcount increment causing this bug, and I
think I may have uncovered some evidence that could get us closer to a
fix. I've added opcode dumps to zend_execute.c with a well-placed perl
command, so as to see the instructions as they're executed.

All of the following has been performed against a clean snapshot of
PHP4
CVS HEAD.

Given the following script, containing one class with two methods
differing only by a silence operator:

  <?php
    class foo
    {
      function &method1() {
        return $this->foo;
      }

      function &method2() {
        return @$this->foo;
      }
    }

    $i = new foo();
    $i->method1();
    echo "\n";
    $i->method2();
  ?>

The following opcodes pass throuch the main switch() in execute(), in
this order:

  ZEND_NOP
  ZEND_NEW
  ZEND_JMP_NO_CTOR
  ZEND_FETCH_W
  ZEND_FETCH_LOCAL
  ZEND_ASSIGN
  ZEND_FETCH_W
  ZEND_FETCH_LOCAL
  ZEND_INIT_FCALL_BY_NAME
  ZEND_DO_FCALL_BY_NAME
  ZEND_FETCH_W
  ZEND_FETCH_LOCAL
  ZEND_FETCH_OBJ_W
  ZEND_RETURN
  ZEND_ECHO
  ZEND_FETCH_W
  ZEND_FETCH_LOCAL
  ZEND_INIT_FCALL_BY_NAME
  ZEND_DO_FCALL_BY_NAME
  ZEND_BEGIN_SILENCE
  ZEND_FETCH_R
  ZEND_FETCH_LOCAL
  ZEND_FETCH_OBJ_R
  ZEND_END_SILENCE
  ZEND_RETURN
  ZEND_RETURN

Here, we see the object property which will eventually become the
return
value of method1() being fetched by the engine with ZEND_FETCH_OBJ_W,
which triggers a zend_fetch_property_address(..., BP_VAR_W) from
zend_execute.c:1354, eventually bumping the reference count in
zend_fetch_property_address_inner:
  
  case BP_VAR_W: {
      zval *new_zval = &EG(uninitialized_zval);
      new_zval->refcount++;
      zend_hash_update(ht, prop_ptr->value.str.val, ...snip...);
    }

However, it seems the addition of the silence operator (which wouldn't
have an effect on the read/write status of the fetch or the refcount,
I
wouldn't think) makes the engine fetch with ZEND_FETCH_OBJ_R;
eventually
triggering another branch of the switch in
zend_get_property_address_inner:
  
  case BP_VAR_R:
    zend_error(E_NOTICE,"Undefined property:  %s",
prop_ptr->value.str.val);
    /* break missing intentionally */
  case BP_VAR_IS:
    retval = &EG(uninitialized_zval_ptr);
    break;

Which omits the increment of the reference count. There is a call to
AI_USE_PTR() on the read path that isn't on the write path, but that
looks like it doesn't touch the refcount of anything.

So, anyway.

I may be completely off in left-field here; apologies if you've made
it
this far and none of this represents any sort of sane thinking. :)
But,
is it possible that the silence operator, when applied to a fetch of
an
object property that is returned by reference, is being miscompiled as
ZEND_FETCH_OBJ_R rather than ZEND_FETCH_OBJ_W?

(Be gentle with replies; this is the first time I've ever really
touched
the Zend Engine's guts.)


Previous Comments:
------------------------------------------------------------------------

[2003-03-31 17:03:45] [EMAIL PROTECTED]

(pasted from bug #22996) user supplied comment & backtrace

What I did:

Compiled 4.3.2RC1 on my Sun Ultra10/Sparc64 NetBSD 1.6.

Used:
./configure --enable-debug --with-apxs
--with-session=shared,/usr/pkg/lib/php/20
020429  --with-gettext=shared,/usr/pkg/lib/php/20020429
--with-pcre=shared,/usr/
pkg/lib/php/20020429

Ran make test and one of the tests that failed follows:

Segmentation fault - core dumped
FAIL Bug #22510 (segfault among complex references)
[tests/lang/bug22510.phpt]

So, I ran gdb and the backtrace follows:

gdb
GNU gdb 5.0nb1
Copyright 2000 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and
you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for
details.
This GDB was configured as "sparc64--netbsd".
(gdb) file sapi/cli/php
Reading symbols from sapi/cli/php...done.
(gdb) r tests/lang/bug22510.phpt
Starting program: /usr/home/mlm/php-4.3.2RC1/sapi/cli/php
tests/lang/bug22510.ph
pt
--TEST--
Bug #22510 (segfault among complex references)
--FILE--
ok1
bar::run1
foo::method1
foo::method1
foo::finalize
done!
ok2
bar::run2
foo::method2
foo::method2
foo::finalize
done!
ok3
bar::run3
foo::method3
foo::method3
foo::finalize
done!
ouch
bar::run1
foo::method1
foo::method1
foo::finalize
[Mon Mar 31 19:20:58 2003]  Script:  'tests/lang/bug22510.phpt'
---------------------------------------
/usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c(271) : Block 0x00442140
status:
Beginning:      Overrun (magic=0x00000000, expected=0x7312F8DC)

Program received signal SIGSEGV, Segmentation fault.
0x40779970 in bcopy () from /usr/lib/libc.so.12
(gdb) bt
#0  0x40779970 in bcopy () from /usr/lib/libc.so.12
#1  0x2a0c60 in _mem_block_check (ptr=0x442180, silent=0, 
    __zend_filename=0x311e78
"/usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c", 
    __zend_lineno=271, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend_alloc.c:649
#2  0x2a0c14 in _mem_block_check (ptr=0x442180, silent=1, 
    __zend_filename=0x311e78
"/usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c", 
    __zend_lineno=271, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend_alloc.c:641
#3  0x29f3cc in _efree (ptr=0x442180, 
    __zend_filename=0x311e78
"/usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c", 
    __zend_lineno=271, __zend_orig_filename=0x0, __zend_orig_lineno=0)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend_alloc.c:217
#4  0x2d42d4 in zend_assign_to_variable_reference (result=0x4c0408, 
    variable_ptr_ptr=0x4c7658, value_ptr_ptr=0x4ae658,
Ts=0xffffffffffffaa50)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c:271
#5  0x2d960c in execute (op_array=0x4b7c40)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c:1354
#6  0x2dae3c in execute (op_array=0x4b7040)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend_execute.c:1650
#7  0x2be5dc in zend_execute_scripts (type=8, retval=0x0,
file_count=3)
    at /usr/home/mlm/php-4.3.2RC1/Zend/zend.c:864
#8  0x261a14 in php_execute_script (primary_file=0xffffffffffffd950)
---Type <return> to continue, or q <return> to quit---
    at /usr/home/mlm/php-4.3.2RC1/main/main.c:1636
#9  0x2e3f00 in main (argc=2, argv=0xffffffffffffdae8)
    at /usr/home/mlm/php-4.3.2RC1/sapi/cli/php_cli.c:753
#10 0x12429c in ___start ()
(gdb) quit

Trying desprately to find a release that works on Sparc64,

So, let me know what I can do to help debug this,

Thank You,
Mike Marshall


------------------------------------------------------------------------

[2003-03-04 08:21:37] php at codewhore dot org

Here's another far more compact version:

<?php

  class module
  {
    var $list;

    function finalize()
    {
      $cl =& $this->list;
    }

    function method(&$controller)
    {
      $controller->get();
    }
  }

  class controller
  {
    function &get()
    {
      return @$this->foo;
    }

    function call()
    {
      call_user_func_array($this->sym, array(&$this));
    }

    function load()
    {
      $instance =& new module();
      $this->instance =& $instance;
      $this->sym = array(&$instance, 'method');
    }

    function run()
    {
      $this->load();
      $this->call();
      $this->call();
    }
  }

  class application
  {
    function run(&$controller)
    {
      $removing_this_global_usage_prevents_segv = @$_GET['x'];
      $controller->run();
    }
  }

  $controller = new controller();
  application::run($controller);
  $controller->instance->finalize();

?>

------------------------------------------------------------------------

[2003-03-03 15:35:00] php at codewhore dot org

Hi:

Thanks for waiting. Below is a test case which I've used to
reproducibly crash 4.3.0 and 4.3.2-dev on three seperate machines.
Sorry it's so long, but this is the absolute minimum I was able to come
up with. I haven't captured another backtrace for this particular case
yet, but I'd be happy to do so if you'd like.

---- >8 --- cut here --- 8< ----

<?php

  class module
  {
    function module(&$controller)
    {
      $this->controller =& $controller;
    }
  }

  class runnable_module extends module
  {
    function initialize() { }
    function finalize()   { }
    function method()     { }
  }


  class first extends runnable_module
  {
    function method()
    {
      $data =& $this->controller->get($data);
    }
  }


  class second extends runnable_module
  {
    function initialize()
    {
      $this->list = array();
    }

    function finalize()
    {
      echo "About to get SIGSEGV...\n";
      $cl =& $this->list;
      echo "Shouldn't see this\n";
    }
  }


  class controller
  {
    function finalize()
    {
      foreach ($this->module_list as $k => $x)
        $this->module_list[$k]->finalize();
    }

    function &get($name)
    {
      return @$this->vars[$name];
    }

    function call($function)
    {
      $symbol =& $this->symtab[$function][0];
      call_user_func($symbol, array());
    }

    function load($name, $method)
    {
      $instance =& new $name($this);
      $instance->initialize();
      $this->module_list[$name] =& $instance;
      $this->symtab[$name] = array(array(&$instance, $method));
    }

    function run()
    {
      $this->load('first', 'method');
      $this->load('second', 'method');
      $this->call('first');
      $this->call('first');
    }
  }


  class application
  {
    function application(&$controller)
    {
      $this->controller =& $controller;
    }

    function run()
    {
      $controller =& $this->controller;
      $removing_this_global_usage_prevents_segv = $_GET['x'];
      $controller->run();
    }
  }


  $controller = new controller();
  $app = new application($controller);
  $app->run();
  $controller->finalize();

?>

---- >8 --- cut here --- 8< ----

Thanks again,
- Dave

------------------------------------------------------------------------

[2003-03-03 11:36:18] [EMAIL PROTECTED]

keep at feedback status until the asked feedback is actually given..


------------------------------------------------------------------------

[2003-03-03 07:47:15] php at codewhore dot org

I'm working on it - there's a ton of code here, and it's proving
difficult to pare it down to a simple test case. However, I hope to
have one posted by the end of the day today.

Thanks.

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/22510

-- 
Edit this bug report at http://bugs.php.net/?id=22510&edit=1

Reply via email to