From ff9a22782a7d28b11af0ff2d3948a196ab12d003 Mon Sep 17 00:00:00 2001 From: Emiel Bruijntjes Date: Tue, 16 Dec 2014 12:47:11 +0100 Subject: fix issue #151, chaining method calls was not working as it should because 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 --- zend/classimpl.cpp | 4 ++-- zend/object.cpp | 6 ++++-- zend/objectimpl.h | 6 +++++- zend/value.cpp | 7 ++++++- 4 files changed, 17 insertions(+), 6 deletions(-) (limited to 'zend') diff --git a/zend/classimpl.cpp b/zend/classimpl.cpp index 9c28a0a..e42605e 100644 --- a/zend/classimpl.cpp +++ b/zend/classimpl.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(); diff --git a/zend/object.cpp b/zend/object.cpp index 4af6204..22431fe 100644 --- a/zend/object.cpp +++ b/zend/object.cpp @@ -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 operator=(Value(base)); diff --git a/zend/objectimpl.h b/zend/objectimpl.h index d72ddbd..4d20f3c 100644 --- a/zend/objectimpl.h +++ b/zend/objectimpl.h @@ -62,9 +62,10 @@ public: * * @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 @@ public: // 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; } diff --git a/zend/value.cpp b/zend/value.cpp index 501feb7..959dbe7 100644 --- a/zend/value.cpp +++ b/zend/value.cpp @@ -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; -- cgit v1.2.3