On Wednesday 04 December 2013 16:01:03 Frank Reininghaus wrote: > Hi, > > 2013/11/30 Kevin Funk: > > Hey guys, > > > > My recent attempts to make KDevelop shine on Windows revealed some odd > > behaviour inside kdelibs. > > > > I need some help in order to find the right approach to fix an at least 3 > > year old bug [1] ultimately caused by the use of a static member object > > in the KCompTreeNode class (kcompletion.h) in kdelibs. Please see the > > attached bug report [2]. > > > > Note that the error *only shows up on Windows*, on Linux we don't have > > this > > problem. I'll try to explain what's wrong in this mail. > > > > The actual issue: > > - KDevelop running: > > - We have an instance of KateGlobal owned by KateFactory, > > > > a plugin loaded by KDevelop > > > > - Some descendant of KateGlobal (KateCmd) owns a KCompTreeNode instance > > - KCompTreeNode uses a custom allocator for creating/deleting instances > > > > of itself, holds a static member of type KZoneAllocactor for that > > > > - KZoneAllocator holds the memory for all the instantiated KCompTreeNodes > > > > So we have the following object ownership (some levels omitted): > > - KateFactory > > > > KateGlobal > > > > KCompTreeNode > > > > KZoneAllocator (static) > > > > When closing KDevelop *under Linux*: > > - ~KateFactory, via QObjectCleanupHandler during __run_exit_handlers > > (glibc)> > > ~KateGlobal, via call to KateGlobal::decRef() > > > > ~KCompTreeNode > > > > - ~KZoneAllocator, during __cxa__finalize (glibc) > > > > The order is fine in this case. No segfaults. > > > > However, on Windows the destruction order is different (and I cannot > > really > > explain why). When closing KDevelop *under Windows*: > > - ~KZoneAllocator is called first, via > > > > "kdeui.dll!`dynamic atexit destructor for > > 'KCompTreeNode::alloc''()" > > > > - ~KateFactory, via QObjectCleanupHandler > > > > ~KateGlobal > > > > Call to KCompTreeNode::removeItem() > > > > => Crash because memory for the KCompTreeNode instances was already freed > > > > by ~KZoneAllocator > > > > I wonder how to fix that: > > The easiest solution obviously: Get rid off the custom allocator in > > KCompTreeNode. Having a class owning its custom allocator is just plain > > wrong, right? But removing that probably has performance impacts. (Does > > anyone have benchmarks here?) > > well, having a custom allocator may have some benefits. I guess that > KCompletion uses one to ensure that all KCompTreeNodes are close to > each other in memory and thus to reduce cache misses? I don't know how > much dropping the custom allocator would affect the performance, one > would have to do some benchmarking with typical KCompletion use cases. I agree that it might be a good performance improvement. But I want to note neither KDevelop nore Kate uses this technique for its code completion in the editor. And we probably have much more completion tree nodes than a usual KCompletion user. I just mention this to show that removing this performance improvement should not kill the performance, rather decrease it slightly. > > Just using K_GLOBAL_STATIC for the KZoneAllocator instance doesn't help > > either. I get the same destruction order + crash with that on Windows. > > > > Dynamic allocation inside KCompTreeNode doesn't work either, because > > KZoneAllocator needs to be there *before* the first KCompTreeNode is > > created and needs to there *until* the last one has been destroyed. > > > > Any ideas? > > Well, here is one idea (untested): use a > QSharedPointer to ensure that the KZoneAllocator is > not destroyed before the last KCompletion instance using it. > > Replace > > static KZoneAllocator alloc; > > in KCompTreeNode by > > static QSharedPointer alloc; > > and, in kcompletion.cpp, > > KZoneAllocator KCompTreeNode::alloc(8192); > > by > > QSharedPointer KCompTreeNode::alloc; > > In KCompTreeNode's operator new/delete, replace "alloc." by "alloc->". > > Furthermore, add a QSharedPointer member to > KCompletionPrivate. In KCompletionPrivate's constructor, first check > if KCompTreeNode::alloc isNull(), initialize it if that is not the > case, and then copy "alloc" to the new member. > > I think that this might work, and it might also improve application > start-up time because the KZoneAllocator would only be initialized on > first use of a KCompletion object. Yes, that might work. Kevin, could you try it out? Bye -- Milian Wolff mail@milianw.de http://milianw.de >> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<