KFileItemActions - why does it remember the actions it created, and deletes them?

David Faure faure at kde.org
Mon Dec 30 12:43:57 GMT 2013


On Friday 13 December 2013 11:28:01 Frank Reininghaus wrote:
> Hi,
> 
> 2013/12/13 Frank Reininghaus:
> > Hi,
> > 
> > thanks David for the detailed reply, and sorry for not reading the
> > documentation before asking stupid questions ;-)
> > 
> > 2013/12/12 David Faure:
> >> On Thursday 12 December 2013 18:38:23 Frank Reininghaus wrote:
> >>> 1. In the openItemContextMenu() member of DolphinContextMenu, which
> >>> inherits KMenu, we create a KFileItemActions instance on the stack,
> >>> and use it to add actions to "this". The actions thus become children
> >>> of "this".
> >> 
> >> Let me quote from the KFileItemActions documentation:
> >>     /**
> >>     
> >>      * Set the parent widget for any dialogs being shown.
> >>      *
> >>      * This should normally be your mainwindow, not a popup menu,
> >>      * so that it still exists even after the popup is closed
> >>      * (e.g. error message from KRun) and so that QAction::setStatusTip
> >>      * can find a statusbar, too.
> >>      */
> >>     
> >>     void setParentWidget(QWidget* widget);
> >> 
> >> *not a popup menu* :-)
> >> 
> >> The documentation is incomplete though - what it forgets to say (oops),
> >> is
> >> that this parent widget will also be the parent of the actions.
> >> 
> >> I can't remember why it works this way, but at least I think you have an
> >> easy solution: call setParentWidget(mainwindow).
> > 
> > Actually, we do call
> > 
> > fileItemActions.setParentWidget(m_mainWindow);
> > 
> > already in DolphinContextMenu::addServiceActions(KFileItemActions&
> > fileItemActions).
> > 
> > Hm. The user said that he closed the Dolphin window by clicking the
> > "X" in the top-right corner of the window. So it seems that both the
> > main window and its context menu child somehow were deleted inside the
> > menu's exec() method with the nested event loop. Now I see two ways to
> > explain the crash:
> > 
> > 1. The mainwindow, which is the owner of the QActions created by the
> > KFIleItemActions instance, somehow gets deleted, and thus deletes its
> > children, including the actions. Therefore, the KFileItemActions
> > destructor tries to delete dangling pointers (I see nothing in
> > kfileitemactions.cpp that prevents appending the created actions to
> > m_ownActions, and deleting them in the destructor, if a parent widget
> > has been set?).
> > 
> > 2. Another problem might be that after returning from the event loop,
> > we are inside DolphinContextMenu::openItemContextMenu(), the method of
> > a deleted object. Therefore, accessing local variables of that
> > function, living on the stack, might not be really safe, right? Just
> > calling KFileItemAction's destructor might be enough to cause trouble
> > then. I think that this could be resolved by allocating the
> > KFileItemActions instance on the heap and setting the context menu as
> > the parent.
> > 
> > Maybe I'll try to do some experiments. If I could only reproduce the
> > crash...
> quick update: I can reproduce the crash now, see
> 
> https://bugs.kde.org/show_bug.cgi?id=259089#c21
> 
> Closing Dolphin with a 5 second delay using
> 
> sleep 5; qdbus `qdbus | grep dolphin`
> /dolphin/Dolphin_1/actions/file_quit trigger
> 
> and then opening the context menu did the trick.
> 
> It seems that solution 2 (allocating the KFileItemActions on the heap
> with the context menu as the parent) solves the problem.
> 
> BTW, the DolphinPart in Konqueror, which uses KonqPopupMenu, does not
> suffer from this problem, because the KFileItemActions instance is a
> member of KonqPopupMenuPrivate (which is destructed before we return
> from the nested event loop when trying to reproduce the bug with the
> "quit via D-Bus" method).
> 
> Still, I'm wondering if KFileItemActions should really delete all
> actions it created, even if they belong to a widget that has been set
> with setParentWidget(QWidget*). It works fine if KFileItemActions is
> destroyed *before* the widget, because parent QObjects listen to the
> 'destroyed' signal, but if the destruction order is different for some
> reason, then we might get a crash because we try to delete dangling
> pointers, right?

Right.

I think the parent for the actions should be the KFileItemActions instance 
instead. That would make all use cases happy, and follow the principle of 
least surprise, right?

-- 
David Faure, faure at kde.org, http://www.davidfaure.fr
Working on KDE, in particular KDE Frameworks 5





More information about the kfm-devel mailing list