summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-12-16 12:47:11 +0100
committerEmiel Bruijntjes <emiel.bruijntjes@copernica.com>2014-12-16 12:47:11 +0100
commitff9a22782a7d28b11af0ff2d3948a196ab12d003 (patch)
tree3fcb8020cb0dce094abefbbecb83055fc31ed1fd
parentda4de6cb1097471b2659c102d55a646cbc9e0f41 (diff)
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
-rw-r--r--zend/classimpl.cpp4
-rw-r--r--zend/object.cpp6
-rw-r--r--zend/objectimpl.h6
-rw-r--r--zend/value.cpp7
4 files changed, 17 insertions, 6 deletions
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;