From 2f4da0f0b0df17ad05ac34e59b17a49d2aa9b5c7 Mon Sep 17 00:00:00 2001 From: "Gustavo J. A. M. Carneiro" Date: Mon, 1 Oct 2007 14:33:17 +0100 Subject: [PATCH] Make Object::QueryInterface and AddInterface check for the aggregate refcount instead of the object refcount, reason explained in a comment near Object::CheckLoose. Add the same check also to TraceConnect/Disconnect and GetTraceResolver. --- src/core/object.cc | 35 ++++++++++++++++++++++++++++++----- src/core/object.h | 1 + 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/core/object.cc b/src/core/object.cc index 1c6d58772..1049b6cab 100644 --- a/src/core/object.cc +++ b/src/core/object.cc @@ -192,7 +192,7 @@ Object::~Object () Ptr Object::DoQueryInterface (InterfaceId iid) const { - NS_ASSERT (Check ()); + NS_ASSERT (CheckLoose ()); const Object *currentObject = this; do { NS_ASSERT (currentObject != 0); @@ -227,24 +227,26 @@ Object::AddInterface (Ptr o) { NS_ASSERT (!m_disposed); NS_ASSERT (!o->m_disposed); - NS_ASSERT (Check ()); - NS_ASSERT (o->Check ()); + NS_ASSERT (CheckLoose ()); + NS_ASSERT (o->CheckLoose ()); Object *other = PeekPointer (o); Object *next = m_next; m_next = other->m_next; other->m_next = next; - NS_ASSERT (Check ()); - NS_ASSERT (o->Check ()); + NS_ASSERT (CheckLoose ()); + NS_ASSERT (o->CheckLoose ()); } void Object::TraceConnect (std::string path, const CallbackBase &cb) const { + NS_ASSERT (CheckLoose ()); GetTraceResolver ()->Connect (path, cb, TraceContext ()); } void Object::TraceDisconnect (std::string path, const CallbackBase &cb) const { + NS_ASSERT (CheckLoose ()); GetTraceResolver ()->Disconnect (path, cb); } @@ -264,6 +266,7 @@ Object::DoDispose (void) Ptr Object::GetTraceResolver (void) const { + NS_ASSERT (CheckLoose ()); Ptr resolver = Create (this); return resolver; @@ -275,6 +278,28 @@ Object::Check (void) const return (m_count > 0); } +/* In some cases, when an event is scheduled against a subclass of + * Object, and if no one owns a reference directly to this object, the + * object is alive, has a refcount of zero and the method ran when the + * event expires runs against the raw pointer which means that we are + * manipulating an object with a refcount of zero. So, instead we + * check the aggregate reference count. + */ +bool +Object::CheckLoose (void) const +{ + uint32_t refcount = 0; + const Object *current = this; + do + { + refcount += current->m_count; + current = current->m_next; + } + while (current != this); + + return (refcount > 0); +} + void Object::MaybeDelete (void) const { diff --git a/src/core/object.h b/src/core/object.h index 36aa3a384..34ce9fe38 100644 --- a/src/core/object.h +++ b/src/core/object.h @@ -186,6 +186,7 @@ private: TraceResolver::SourceCollection *collection) const; void DoTraceAll (std::ostream &os, const TraceContext &context) const; bool Check (void) const; + bool CheckLoose (void) const; void MaybeDelete (void) const; mutable uint32_t m_count; InterfaceId m_iid;