Skip to content
Browse files

fix issue #151, chaining method calls was not working as it should be…

…cause the per-object refcount was not updated correctly, which caused an object to be destructed even when it already was assigned to a different variable
  • Loading branch information...
EmielBruijntjes committed Dec 16, 2014
1 parent da4de6c commit ff9a22782a7d28b11af0ff2d3948a196ab12d003
Showing with 17 additions and 6 deletions.
  1. +2 −2 zend/classimpl.cpp
  2. +4 −2 zend/object.cpp
  3. +5 −1 zend/objectimpl.h
  4. +6 −1 zend/value.cpp
@@ -534,7 +534,7 @@ zend_object_value ClassImpl::cloneObject(zval *val TSRMLS_DC)
result.handlers = impl->objectHandlers();

// store the object
ObjectImpl *new_object = new ObjectImpl(entry, cpp TSRMLS_CC);
ObjectImpl *new_object = new ObjectImpl(entry, cpp, 1 TSRMLS_CC);

// store the object in the object cache
result.handle = new_object->handle();
@@ -1195,7 +1195,7 @@ zend_object_value ClassImpl::createObject(zend_class_entry *entry TSRMLS_DC)
result.handlers = impl->objectHandlers();

// create the object in the zend engine
ObjectImpl *object = new ObjectImpl(entry, cpp TSRMLS_CC);
ObjectImpl *object = new ObjectImpl(entry, cpp, 1 TSRMLS_CC);

// store the object in the object cache
result.handle = object->handle();
@@ -40,8 +40,10 @@ Object::Object(const char *name, Base *base) : Value()
if (!entry) throw FatalError(std::string("Unknown class name ") + name);

// construct an implementation (this will also set the implementation
// member in the base object)
new ObjectImpl(entry, base TSRMLS_CC);
// member in the base object), this is a self-destructing object that
// will be destructed when the last reference to it has been removed,
// we already set the reference to zero
new ObjectImpl(entry, base, 0 TSRMLS_CC);

// now we can store it
@@ -62,9 +62,10 @@ class ObjectImpl
* @param entry Zend class entry
* @param base C++ object that already exists
* @param refcount The initial refcount for the object
* @param tsrm_ls Optional threading data
ObjectImpl(zend_class_entry *entry, Base *base TSRMLS_DC)
ObjectImpl(zend_class_entry *entry, Base *base, int refcount TSRMLS_DC)
// allocate a mixed object (for some reason this does not have to be deallocated)
_mixed = (MixedObject *)emalloc(sizeof(MixedObject));
@@ -117,6 +118,9 @@ class ObjectImpl
// seem to be necessary...
_handle = zend_objects_store_put(php(), (zend_objects_store_dtor_t)destructMethod, (zend_objects_free_object_storage_t)freeMethod, NULL TSRMLS_CC);

// set the initial refcount (if it is different than one, because one is the default)
if (refcount != 1) EG(objects_store).object_buckets[_handle].bucket.obj.refcount = refcount;

// the object may remember that we are its implementation object
base->_impl = this;
@@ -188,7 +188,9 @@ Value::Value(const Base *object)
// there are two options: the object was constructed from user space,
// and is already linked to a handle, or it was constructed from C++
// space, and no handle does yet exist, find the implementation object
// space, and no handle does yet exist. But if it was constructed from
// C++ space and not yet wrapped, this Value constructor should not be
// called directly, but first via the derived Php::Object class.
auto *impl = object->implementation();

// do we have a handle?
@@ -205,6 +207,9 @@ Value::Value(const Base *object)
// we have to lookup the object in the object-table
zend_object_store_bucket *obj_bucket = &EG(objects_store).object_buckets[impl->handle()];

// there is one more reference to the object
obj_bucket->bucket.obj.refcount += 1;

// this is copy-pasted from zend_objects.c - and it is necessary too!
if (!obj_bucket->bucket.obj.handlers) obj_bucket->bucket.obj.handlers = &std_object_handlers;

1 comment on commit ff9a227


This comment has been minimized.

Copy link

taylorren commented on ff9a227 Dec 16, 2014

Thanks! That is really a quick fix!

Please sign in to comment.
You can’t perform that action at this time.