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. I've appended this to the entry on bugs.php.net
as well.)


Thanks in advance,

- Dave
  [EMAIL PROTECTED]


-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to