ImplCycleCollectionTraverse for nsRefPtrHashtable doesn't traverse its keys
Categories
(Core :: Cycle Collector, defect)
Tracking
()
People
(Reporter: zbraniecki, Unassigned)
Details
In bug 1517880 we encountered a bug where this table:
nsRefPtrHashtable<nsRefPtrHashKey<Element>, nsXULPrototypeElement>
mL10nProtoElements;
doesn't NS_IMPL_CYCLE_COLLECTION_TRAVERSE/NS_IMPL_CYCLE_COLLECTION_UNLINK its keys which lead to leaks.
Comment 1•5 years ago
|
||
This is actually an issue for all the XPCOM hashtables, since they could all be using nsRefPtrHashKey...
Updated•5 years ago
|
Comment 2•5 years ago
|
||
I'm pretty surprised this hasn't come up before. Maybe people have just been hacking around it. A fix for this will have to audit all existing users.
Presumably a proper fix will require some kind of SFINAE thing that attempts to get a traverse for the key, and falls back to not having one. This is implemented as ImplCycleCollectionTraverse in nsRefPtrHashtable. Ideally, this fix would also be applied to all other users of these hash table keys.
Updated•5 years ago
|
Comment 3•5 years ago
|
||
(In reply to Zibi Braniecki [:zbraniecki][:gandalf] from comment #0)
In bug 1517880 we encountered a bug where this table:
nsRefPtrHashtable<nsRefPtrHashKey<Element>, nsXULPrototypeElement> mL10nProtoElements;
doesn't NS_IMPL_CYCLE_COLLECTION_TRAVERSE/NS_IMPL_CYCLE_COLLECTION_UNLINK its keys which lead to leaks.
It looks like the traverse implementation is correct:
https://searchfox.org/mozilla-central/source/xpcom/ds/nsRefPtrHashtable.h#79-86
Maybe the problem is that we don't have the right overloads for iter.UserData()
; nsTHashtable
's implementation of the same is slightly different:
https://searchfox.org/mozilla-central/source/xpcom/ds/nsTHashtable.h#446-454
Is the right thing to note children, as nsRefPtrHashtable
does, or to directly traverse the children, as nsTHashtable
does?
Does the unlink implementation need to call unlink on its elements?
https://searchfox.org/mozilla-central/source/xpcom/ds/nsRefPtrHashtable.h#74-77
https://searchfox.org/mozilla-central/source/xpcom/ds/nsTHashtable.h#441-444
Comment 4•5 years ago
|
||
The problem with the traverse is that it is traversing the values in the hash table, but not the keys.
It needs an additional line like
CycleCollectionNoteChild(aCallback, iter.Key(), aName, aFlags);
...except of course, only when the hash table has a refcounted reference to the key.
Maybe we could restructure these iterators to deal with EntryTypes for more code reuse?
Unlink is fine. We clear the hashtable, which will break any cycles.
Comment 5•5 years ago
|
||
(In reply to Andrew McCreight [:mccr8] from comment #4)
Maybe we could restructure these iterators to deal with EntryTypes for more code reuse?
Well, the iterator, not the entry.
Comment 6•5 years ago
|
||
Maybe people have just been hacking around it.
https://searchfox.org/mozilla-central/rev/0bcdfa99339c0512e3730903835fb6f8ed45e3c4/dom/animation/EffectCompositor.cpp#57 is a slightly more complicated case...
We'd presumably want to look at the CC story around https://searchfox.org/mozilla-central/search?q=symbol:T_nsRefPtrHashKey&redirect=false
So fwiw, for the specific case of nsRefPtrHashtable, I get a compiling tree when I do this:
// We can't partially-specialize functions, but we can
// partially-specialize classes.
template<typename KeyClass>
struct KeyTraverser {
static inline void Traverse(nsCycleCollectionTraversalCallback& aCallback,
typename KeyClass::KeyType aKey,
const char* aName,
uint32_t aFlags) {
// Default impl does nothing
}
};
template<typename T>
struct KeyTraverser<nsRefPtrHashKey<T>> {
static inline void Traverse(nsCycleCollectionTraversalCallback& aCallback,
T* aKey,
const char* aName,
uint32_t aFlags) {
CycleCollectionNoteChild(aCallback, aKey, aName, aFlags);
}
};
class nsAtom;
template<>
struct KeyTraverser<nsRefPtrHashKey<nsAtom>> {
static inline void Traverse(nsCycleCollectionTraversalCallback& aCallback,
nsAtom* aKey,
const char* aName,
uint32_t aFlags) {
// Atoms don't need to be CCed
}
};
and then
KeyTraverser<K>::Traverse(aCallback, iter.Key(), aName, aFlags);
in the iteration loop in ImplCycleCollectionTraverse
for nsRefPtrHashtable
. But again, we'd ideally like to do this for all hashtables, so maybe we can move the ImplCycleCollectionTraverse
bit to base hashtable and then have specializations like that for both the key and the value?
Updated•5 years ago
|
Updated•4 years ago
|
Updated•2 years ago
|
Updated•2 years ago
|
Description
•