diff options
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/CHANGES | 3 | ||||
-rwxr-xr-x | cpp/include/Ice/GC.h | 2 | ||||
-rwxr-xr-x | cpp/include/Ice/GCShared.h | 11 | ||||
-rwxr-xr-x | cpp/src/Ice/GC.cpp | 27 | ||||
-rwxr-xr-x | cpp/src/Ice/GCShared.cpp | 11 | ||||
-rw-r--r-- | cpp/src/slice2cpp/Gen.cpp | 34 | ||||
-rw-r--r-- | cpp/test/Ice/gc/Client.cpp | 25 |
7 files changed, 82 insertions, 31 deletions
diff --git a/cpp/CHANGES b/cpp/CHANGES index 6b85e1e7619..40506d62d70 100644 --- a/cpp/CHANGES +++ b/cpp/CHANGES @@ -1,6 +1,9 @@ Changes since version 3.0.0 --------------------------- +- Fixed a bug in the class garbage collector that could result in double + deallocation of class instances. + - IceUtil::Time::toString() has been deprecated and should no longer be used. Instead, use IceUtil::Time::toDateTime() to get a date and time string. (toString() will continue to work as a synonym for diff --git a/cpp/include/Ice/GC.h b/cpp/include/Ice/GC.h index 88bad7e11b9..80a617f0dc8 100755 --- a/cpp/include/Ice/GC.h +++ b/cpp/include/Ice/GC.h @@ -13,7 +13,7 @@ #include <IceUtil/Config.h> #include <IceUtil/Thread.h> #include <IceUtil/Monitor.h> -#include <IceUtil/Mutex.h>
+#include <IceUtil/Mutex.h> #include <Ice/Config.h> namespace IceInternal diff --git a/cpp/include/Ice/GCShared.h b/cpp/include/Ice/GCShared.h index 047caffac8d..5090ddd12e2 100755 --- a/cpp/include/Ice/GCShared.h +++ b/cpp/include/Ice/GCShared.h @@ -40,9 +40,15 @@ public: virtual void __incRef(); // First derived class with class data members overrides this. virtual void __decRef(); // Ditto. + virtual void __addObject(GCObjectMultiSet&) {} // Ditto. + virtual bool __usesClasses() { return false; } // Ditto. + virtual int __getRef() const; virtual void __setNoDelete(bool); + virtual void __gcReachable(GCObjectMultiSet&) const = 0; + virtual void __gcClear() = 0; + int __getRefUnsafe() const { return _ref; @@ -53,13 +59,8 @@ public: --_ref; } - virtual void __gcReachable(GCObjectMultiSet&) const = 0; - virtual void __gcClear() = 0; - protected: - static void __addObject(GCObjectMultiSet&, GCShared*); - int _ref; bool _noDelete; diff --git a/cpp/src/Ice/GC.cpp b/cpp/src/Ice/GC.cpp index 938ee6fab56..463eff13fd4 100755 --- a/cpp/src/Ice/GC.cpp +++ b/cpp/src/Ice/GC.cpp @@ -163,10 +163,11 @@ IceInternal::GC::collectGarbage() // // gcObjects contains the set of class instances that have at least one member of class type, // that is, gcObjects contains all those instances that can point at other instances. - // Call this the the candiate set. + // Call this the candidate set. // Build a multiset of instances that are immediately (not recursively) reachable from instances - // in the candidate set. This adds leaf nodes (class instances that are pointed at, but cannot - // point at anything themselves) to the multiset. + // in the candidate set. This adds adds all immediately reachable nodes to the reachable set, but + // does not add nodes that cannot participate in a cycle (class instances that are pointed at, but cannot + // point at anything themselves because they have no class members) to the multiset. // GCObjectMultiSet reachable; { @@ -177,7 +178,7 @@ IceInternal::GC::collectGarbage() } // - // Create a map of reference counts. + // Create a map of reference counts of all objects in the reachable set. // typedef map<GCShared*, int> ObjectCounts; ObjectCounts counts; @@ -188,7 +189,7 @@ IceInternal::GC::collectGarbage() pos = counts.find(*i); // - // If this instance is not in the counts set yet, insert it with its reference count - 1; + // If this instance is not in the counts map yet, insert it with its reference count - 1; // otherwise, decrement its reference count. // if(pos == counts.end()) @@ -203,8 +204,8 @@ IceInternal::GC::collectGarbage() } // - // Any instances with a ref count > 0 are referenced from outside the set of class instances (and therefore - // reachable from the program, for example, via Ptr variable on the stack). Remove these instances + // Any instances with a ref count > 0 are referenced from outside the reachable class instances (and + // therefore reachable from the program, for example, via Ptr variable on the stack). Remove these instances // (and all instances reachable from them) from the overall set of objects. // { @@ -230,7 +231,15 @@ IceInternal::GC::collectGarbage() ObjectCounts::const_iterator i; for(i = counts.begin(); i != counts.end(); ++i) { - i->first->__gcClear(); // Decrement ref count of objects pointed at by this object. + // + // For classes with members that point at potentially-cyclic instances, __gcClear() + // decrements the reference count of those instances and clears the + // corrsponding Ptr members. + // For classes that cannot be part of a cycle (because they do not contain class members) + // and are therefore true leaves, __gcClear() assigns 0 to the corresponding class member, + // which either decrements the ref count or, if it reaches zero, deletes the instance as usual. + // + i->first->__gcClear(); } for(i = counts.begin(); i != counts.end(); ++i) { @@ -255,7 +264,7 @@ IceInternal::GC::collectGarbage() counts.clear(); { - Monitor<Mutex>::Lock sync2(*this); + Monitor<Mutex>::Lock sync(*this); _collecting = false; } diff --git a/cpp/src/Ice/GCShared.cpp b/cpp/src/Ice/GCShared.cpp index 7dc7b05c7a9..b5421f89407 100755 --- a/cpp/src/Ice/GCShared.cpp +++ b/cpp/src/Ice/GCShared.cpp @@ -73,14 +73,3 @@ IceInternal::GCShared::__setNoDelete(bool b) _noDelete = b; gcRecMutex._m->unlock(); } - -void -IceInternal::GCShared::__addObject(GCObjectMultiSet& c, GCShared* p) -{ - gcRecMutex._m->lock(); - if(p) - { - c.insert(p); - } - gcRecMutex._m->unlock(); -} diff --git a/cpp/src/slice2cpp/Gen.cpp b/cpp/src/slice2cpp/Gen.cpp index a80c8b3946b..813f04fa9e4 100644 --- a/cpp/src/slice2cpp/Gen.cpp +++ b/cpp/src/slice2cpp/Gen.cpp @@ -3158,10 +3158,10 @@ Slice::Gen::ObjectVisitor::emitGCFunctions(const ClassDefPtr& p) // // A class can potentially be part of a cycle if it (recursively) contains class - // members. If so, we override __incRef() and __decRef() and, hence, consider instances - // of the class as candidates for collection by the garbage collector. - // We override __incRef() and __decRef() only once, in the basemost potentially cyclic class - // in an inheritance hierarchy. + // members. If so, we override __incRef(), __decRef(), and __addObject() and, hence, consider + // instances of the class as candidates for collection by the garbage collector. + // We override __incRef(), __decRef(), and __addObject() only once, in the basemost potentially + // cyclic class in an inheritance hierarchy. // bool hasBaseClass = !bases.empty() && !bases.front()->isInterface(); bool canBeCyclic = p->canBeCyclic(); @@ -3224,6 +3224,20 @@ Slice::Gen::ObjectVisitor::emitGCFunctions(const ClassDefPtr& p) C << nl << "delete this;"; C << eb; C << eb; + + H << nl << "virtual void __addObject(::IceInternal::GCObjectMultiSet&);"; + + C << sp << nl << "void" << nl << scoped.substr(2) << "::__addObject(::IceInternal::GCObjectMultiSet& _c)"; + C << sb; + C << nl << "_c.insert(this);"; + C << eb; + + H << nl << "virtual bool __usesClasses();"; + + C << sp << nl << "bool" << nl << scoped.substr(2) << "::__usesClasses()"; + C << sb; + C << nl << "return true;"; + C << eb; } // @@ -3279,7 +3293,10 @@ Slice::Gen::ObjectVisitor::emitGCInsertCode(const TypePtr& p, const string& pref if((BuiltinPtr::dynamicCast(p) && BuiltinPtr::dynamicCast(p)->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(p)) { - C << nl << "__addObject(_c, " << prefix << name << ".get());"; + C << nl << "if(" << prefix << name << ')'; + C << sb; + C << nl << prefix << name << "->__addObject(_c);"; + C << eb; } else if(StructPtr s = StructPtr::dynamicCast(p)) { @@ -3330,9 +3347,16 @@ Slice::Gen::ObjectVisitor::emitGCClearCode(const TypePtr& p, const string& prefi { C << nl << "if(" << prefix << name << ")"; C << sb; + C << nl << "if(" << prefix << name << "->__usesClasses())"; + C << sb; C << nl << prefix << name << "->__decRefUnsafe();"; C << nl << prefix << name << ".__clearHandleUnsafe();"; C << eb; + C << nl << "else"; + C << sb; + C << nl << prefix << name << " = 0;"; + C << eb; + C << eb; } else if(StructPtr s = StructPtr::dynamicCast(p)) { diff --git a/cpp/test/Ice/gc/Client.cpp b/cpp/test/Ice/gc/Client.cpp index cf4aa79fb4b..edddb6b4bc2 100644 --- a/cpp/test/Ice/gc/Client.cpp +++ b/cpp/test/Ice/gc/Client.cpp @@ -528,6 +528,31 @@ MyApplication::run(int argc, char* argv[]) cout << "testing leaf nodes... " << flush; { + NNPtr nn = new NN; + nn->l = new NL; + test(getNum() == 2); + Ice::collectGarbage(); + test(getNum() == 2); + } + Ice::collectGarbage(); + test(getNum() == 0); + + { + NLPtr p; + { + NNPtr nn = new NN; + p = new NL; + nn->l = p; + test(getNum() == 2); + Ice::collectGarbage(); + test(getNum() == 2); + } + Ice::collectGarbage(); + test(getNum() == 1); + } + test(getNum() == 0); + + { NNPtr nn = new NN; NLPtr nl = new NL; nn->l = nl; |