Bug 471286

Summary: Infinite loop in ActionToolbar
Product: [Frameworks and Libraries] frameworks-kirigami Reporter: David Edmundson <kde>
Component: generalAssignee: kdelibs bugs <kdelibs-bugs-null>
Status: RESOLVED FIXED    
Severity: normal CC: me, nate, notmart
Priority: NOR Keywords: qt6
Version First Reported In: unspecified   
Target Milestone: Not decided   
Platform: Other   
OS: Linux   
Latest Commit: Version Fixed/Implemented In:
Sentry Crash Report:

Description David Edmundson 2023-06-21 10:06:16 UTC
We lay out, which changes the implicit size, which adds an item, which triggers a relayout.

#550 0x00007fffc271c0f6 in ToolBarLayout::relayout (this=0x5555557f7050)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayout.cpp:306
--Type <RET> for more, q to quit, c to continue without paging--
#551 0x00007fffc27264d4 in operator() (__closure=0x555564e12fd0, incubator=0x555564e12f90)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayoutdelegate.cpp:144
#552 0x00007fffc2727904 in std::__invoke_impl<void, ToolBarLayoutDelegate::createItems(QQmlComponent*, QQmlComponent*, std::function<void(QQuickItem*)>)::<lambda(ToolBarDelegateIncubator*)>&, ToolBarDelegateIncubator*>(std::__invoke_other, struct {...} &) (__f=...) at /usr/include/c++/13.1.1/bits/invoke.h:61
#553 0x00007fffc272765e in std::__invoke_r<void, ToolBarLayoutDelegate::createItems(QQmlComponent*, QQmlComponent*, std::function<void(QQuickItem*)>)::<lambda(ToolBarDelegateIncubator*)>&, ToolBarDelegateIncubator*>(struct {...} &) (__fn=...) at /usr/include/c++/13.1.1/bits/invoke.h:111
#554 0x00007fffc272742e in std::_Function_handler<void(ToolBarDelegateIncubator*), ToolBarLayoutDelegate::createItems(QQmlComponent*, QQmlComponent*, std::function<void(QQuickItem*)>)::<lambda(ToolBarDelegateIncubator*)> >::_M_invoke(const std::_Any_data &, ToolBarDelegateIncubator *&&) (__functor=..., 
    __args#0=@0x7fffff82f520: 0x555564e12f90) at /usr/include/c++/13.1.1/bits/std_function.h:290
#555 0x00007fffc2727e13 in std::function<void (ToolBarDelegateIncubator*)>::operator()(ToolBarDelegateIncubator*) const (this=0x555564e12fd0, __args#0=0x555564e12f90) at /usr/include/c++/13.1.1/bits/std_function.h:591
#556 0x00007fffc2725b6a in ToolBarDelegateIncubator::statusChanged (this=0x555564e12f90, 
    status=QQmlIncubator::Ready)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayoutdelegate.cpp:59
#557 0x00007ffff735fc72 in QQmlIncubatorPrivate::incubate (this=this@entry=0x555564e150e0, i=...)
    at /home/david/projects/kde6/src/qtdeclarative/src/qml/qml/qqmlincubator.cpp:365
#558 0x00007ffff7360254 in QQmlEnginePrivate::incubate (this=0x555555749480, i=..., forContext=...)
    at /home/david/projects/kde6/src/qtdeclarative/src/qml/qml/qqmlincubator.cpp:53
#559 0x00007ffff72f4855 in QQmlComponent::create (this=<optimized out>, incubator=..., context=<optimized out>, 
    forContext=<optimized out>) at /home/david/projects/kde6/src/qtdeclarative/src/qml/qml/qqmlcomponent.cpp:1428
#560 0x00007fffc27258db in ToolBarDelegateIncubator::create (this=0x555564e12f90)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayoutdelegate.cpp:31
#561 0x00007fffc2726b8a in ToolBarLayoutDelegate::createItems(QQmlComponent*, QQmlComponent*, std::function<void (QQuickItem*)>) (this=0x555564e151d0, fullComponent=0x55555588a210, iconComponent=0x55555586a310, callback=...)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayoutdelegate.cpp:175
--Type <RET> for more, q to quit, c to continue without paging--
#562 0x00007fffc271d7c6 in ToolBarLayout::Private::createDelegate (this=0x55555581a9c0, action=0x55555594b130)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayout.cpp:610
#563 0x00007fffc271d4a4 in ToolBarLayout::Private::createDelegates (this=0x55555581a9c0)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayout.cpp:559
#564 0x00007fffc271c47a in ToolBarLayout::Private::calculateImplicitSize (this=0x55555581a9c0)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayout.cpp:374
#565 0x00007fffc271c0f6 in ToolBarLayout::relayout (this=0x5555557f7050)
    at /home/david/projects/kde6/src/frameworks/kirigami/src/toolbarlayout.cpp:306

Reproducible case:



import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami 2.20 as Kirigami

Item {
    width: 300
    height: 200

    Kirigami.InlineMessage {
        anchors {
            left: parent.left
            right: parent.right
            top: parent.top
        }
        text: "This is some text and oh my god it's soooooo long"
        visible: true
        showCloseButton: true
        actions: [
            QQC2.Action {
                icon.name: "edit-bomb"
                text: "I am here, click me"
                onTriggered: {
                    console.warn("Hello World")
                }
            }
        ]
    }
}
Comment 1 ratijas 2023-06-21 12:25:29 UTC
A simpler test case would be just creating an ActionToolBar or ToolBarLayout component directly like this:


import QtQuick 2.15
import org.kde.kirigami 2.20 as Kirigami

Kirigami.ActionToolBar {
    actions: [
        Kirigami.Action {}
    ]
}
Comment 2 Bug Janitor Service 2023-06-26 08:42:30 UTC
A possibly relevant merge request was started @ https://invent.kde.org/frameworks/kirigami/-/merge_requests/1149
Comment 3 Arjen Hiemstra 2023-06-26 10:11:21 UTC
Git commit 04b0ccabcbf51eb08883671a6f62f2564a6cc12e by Arjen Hiemstra.
Committed on 26/06/2023 at 10:07.
Pushed by ahiemstra into branch 'master'.

toolbarlayout: Buffer calls to calculateImplicitSize()

`calculateImplicitSize()` is called by ToolBarLayoutDelegate to update
the implicit size after the delegate knows what its actual size is.
However, since it needs the delegates to determine the size, it will
call `createDelegates()` to update the list of delegates. This works
fine if the delegate is properly async, unfortunately in some cases Qt
will force the delegate creation into sync mode as there is no async
incubation controller. This then creates an infinite recursion as
ToolBarLayout does not yet know that the delegate exists and tries to
create a new one.

To avoid that, we can change implicit size calculation to be a part of
the layout process, only recalculating it when actually needed. Any
explicit calls to recalculate the implicit size will instead invalidate
the implicit size and call `polish()`. This makes relayouting calls
avoid the loop while ensuring layouting has the most up to date
information about delegate sizes.

M  +24   -16   src/toolbarlayout.cpp

https://invent.kde.org/frameworks/kirigami/-/commit/04b0ccabcbf51eb08883671a6f62f2564a6cc12e