<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Crash tearing 2nd-to-last dock out of a floating tabbed group (QDockWidgetGroupWindow) — Windows, Qt 6.11.1]]></title><description><![CDATA[<h1>Crash tearing 2nd-to-last dock out of a floating tabbed group (QDockWidgetGroupWindow) — Windows, Qt 6.11.1</h1>
<p dir="auto">Posting here because the bug tracker login is looping for me; happy for a maintainer<br />
to move this into Jira. Minimal 40-line repro + crash stack below.</p>
<h2>What happens</h2>
<p dir="auto">On Windows, dragging the <strong>second-to-last</strong> dock widget out of a floating tabbed<br />
group (<code>QDockWidgetGroupWindow</code>) crashes with an access violation. The group drops<br />
from 2 members to 1, Qt destroys the group window and reparents the surviving dock<br />
to the main window, and <code>QDockAreaLayoutInfo::reparentWidgets()</code> dereferences a<br />
dangling <code>item.widgetItem</code> while <code>QMainWindowLayout::applyState()</code> replays the<br />
drag's saved layout state.</p>
<ul>
<li>A <strong>3-member</strong> group torn down to 2 does <strong>not</strong> crash — only the transition that<br />
<strong>destroys</strong> the group window (2→1).</li>
<li>It's <strong>not</strong> drag-specific: programmatically removing one member of a 2-member<br />
group via <code>addDockWidget()</code> + <code>setFloating()</code> also crashes, just deferred ~1 s.<br />
Removing both (2→0, empty group) crashes too — so the fault is the group-window<br />
teardown itself.</li>
</ul>
<p dir="auto">Looks like a <strong>Windows</strong> regression / uncovered case of<br />
<a href="https://bugreports.qt.io/browse/QTBUG-118579" target="_blank" rel="noopener noreferrer nofollow ugc">QTBUG-118579</a> (fixed 6.5.4 / 6.6.2 /<br />
6.7.0 for Linux/X11 + macOS). That fix — the <code>qobject_cast&lt;QDockWidgetGroupWindow*&gt;</code><br />
skip in <code>reparentWidgets</code> — is present in 6.11.1 but runs <em>after</em> the faulting<br />
dereference.</p>
<h2>Environment</h2>
<p dir="auto">Qt <strong>6.11.1</strong>, Windows 11, MSVC x64 (reproduced with the stock <code>msvc2022_64</code> shared<br />
kit and with a from-source static build).</p>
<h2>Steps to reproduce</h2>
<ol>
<li>Build &amp; run the program below (3 dock widgets open floating).</li>
<li>Drag two of them together into <strong>one tabbed floating group</strong>.</li>
<li>Drag one of those two tabs back out and drop it. → crash.</li>
</ol>
<h2>Crash stack</h2>
<pre><code>QDockAreaLayoutInfo::reparentWidgets(QWidget*)            qdockarealayout.cpp:2210
QMainWindowLayout::applyState(QMainWindowLayoutState&amp;, bool)  qmainwindowlayout.cpp:3240
QMainWindowLayout::restore(QInternal::SaveStateRule)         qmainwindowlayout.cpp:2727
QDockWidgetPrivate::endDrag(EndDragMode)                     qdockwidget.cpp:833
QDockWidgetPrivate::setFloating(bool)                        qdockwidget.cpp:1485
QDockWidget::setFloating(bool)                              qdockwidget.cpp:1474
QDockWidgetGroupWindow::reparentToMainWindow(QDockWidget*)  qdockwidget.cpp:772
QDockWidgetPrivate::endDrag(EndDragMode)                    qdockwidget.cpp:860
QMainWindowTabBar::mouseReleaseEvent(QMouseEvent*)          qmainwindowlayout.cpp:2111
</code></pre>
<p dir="auto">The AV reads the <code>item.widgetItem</code> value (seen as <code>0xFFFFFFFFFFFFFFFF</code> and<br />
<code>0x0000000100000001</code> across runs — a stale/garbage pointer in <code>item_list</code>):</p>
<pre><code class="language-cpp">// qdockarealayout.cpp, QDockAreaLayoutInfo::reparentWidgets
if (item.widgetItem) {
    QWidget *w = item.widgetItem-&gt;widget();        // &lt;-- AV (item.widgetItem dangling)
    if (qobject_cast&lt;QDockWidgetGroupWindow *&gt;(w)) // QTBUG-118579 skip, runs too late
        continue;
    ...
</code></pre>
<h2>Minimal reproducer</h2>
<p dir="auto"><code>main.cpp</code>:</p>
<pre><code class="language-cpp">#include &lt;QApplication&gt;
#include &lt;QMainWindow&gt;
#include &lt;QDockWidget&gt;
#include &lt;QPlainTextEdit&gt;
#include &lt;QLabel&gt;

int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    QMainWindow w;
    w.resize(1000, 650);
    w.setDockOptions(QMainWindow::AllowTabbedDocks
                   | QMainWindow::AllowNestedDocks
                   | QMainWindow::GroupedDragging);
    w.setCentralWidget(new QLabel("central", &amp;w));

    for (int i = 1; i &lt;= 3; ++i) {
        auto* d = new QDockWidget(QString("Dock %1").arg(i), &amp;w);
        d-&gt;setWidget(new QPlainTextEdit(QString("content %1").arg(i)));
        d-&gt;setAllowedAreas(Qt::AllDockWidgetAreas);
        w.addDockWidget(Qt::LeftDockWidgetArea, d);
        d-&gt;setFloating(true);
        d-&gt;move(120 + i * 80, 120 + i * 70);
        d-&gt;resize(360, 260);
    }

    w.show();
    return app.exec();
}
</code></pre>
<p dir="auto"><code>CMakeLists.txt</code>:</p>
<pre><code class="language-cmake">cmake_minimum_required(VERSION 3.21)
project(qtdockcrash LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()
qt_add_executable(qtdockcrash WIN32 main.cpp)
target_link_libraries(qtdockcrash PRIVATE Qt6::Widgets)
</code></pre>
]]></description><link>https://forum.qt.io/topic/164810/crash-tearing-2nd-to-last-dock-out-of-a-floating-tabbed-group-qdockwidgetgroupwindow-windows-qt-6.11.1</link><generator>RSS for Node</generator><lastBuildDate>Fri, 10 Jul 2026 04:29:05 GMT</lastBuildDate><atom:link href="https://forum.qt.io/topic/164810.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 19 Jun 2026 10:25:59 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Crash tearing 2nd-to-last dock out of a floating tabbed group (QDockWidgetGroupWindow) — Windows, Qt 6.11.1 on Fri, 19 Jun 2026 12:22:36 GMT]]></title><description><![CDATA[<p dir="auto">Thanks Christian — that lines up. I checked the <code>qt/qtbase</code> <strong>6.11 branch</strong> and the fix<br />
is right there in <code>QDockWidgetGroupWindow::reparentToMainWindow()</code><br />
(<code>src/widgets/widgets/qmainwindowlayout.cpp</code>): an early <code>mwLayout-&gt;savedState.clear();</code>,<br />
with a comment that nails the cause:</p>
<pre><code class="language-cpp">mwLayout-&gt;widgetAnimator.abort(dockWidget);

// The saved state is now invalid because it contains
// a reference to the dock widget inside the group window.
// - the dock widget has been reparented.
// - if it was the last dock widget, the group window will be deleted
// =&gt; clear saved state.
mwLayout-&gt;savedState.clear();
</code></pre>
<p dir="auto">That matches the root cause exactly: the drag's <code>savedState</code> snapshot shares<br />
<code>QLayoutItem*</code> with <code>layoutState</code>, <code>reparentToMainWindow()</code> invalidates them, and the<br />
nested <code>setFloating()</code> → <code>endDrag()</code> → <code>restore()</code> replays the stale snapshot in<br />
<code>reparentWidgets()</code> → the AV. (Reassuring to land on the same one-liner independently.)</p>
<p dir="auto">So for anyone hitting this on <strong>6.11.1</strong> before 6.11.2 ships: the one-line backport above<br />
in <code>reparentToMainWindow()</code> fixes it — verified on Windows 11 / Qt 6.11.1 / MSVC x64<br />
(2→1 tear no longer crashes; create/move and the 3→2 tear are unaffected). And once on<br />
<strong>6.11.2 / 6.12</strong> the official fix covers it, so the local patch can just be dropped.</p>
<p dir="auto">Thanks again for the quick pointer!</p>
]]></description><link>https://forum.qt.io/post/838825</link><guid isPermaLink="true">https://forum.qt.io/post/838825</guid><dc:creator><![CDATA[jvenema]]></dc:creator><pubDate>Fri, 19 Jun 2026 12:22:36 GMT</pubDate></item><item><title><![CDATA[Reply to Crash tearing 2nd-to-last dock out of a floating tabbed group (QDockWidgetGroupWindow) — Windows, Qt 6.11.1 on Fri, 19 Jun 2026 12:08:45 GMT]]></title><description><![CDATA[<h2>Root cause found, and a working fix (local qtbase patch)</h2>
<p dir="auto">Tracked this down to <code>QDockWidgetGroupWindow::reparentToMainWindow()</code> in<br />
<code>src/widgets/widgets/qmainwindowlayout.cpp</code>. When the group drops below 2 members and<br />
is torn down, that function reparents the dock and calls <code>setFloating()</code>, which <strong>nests</strong><br />
into <code>QDockWidgetPrivate::endDrag() → QMainWindowLayout::restore()</code>:</p>
<ol>
<li><code>reparentToMainWindow()</code> mutates <code>mwLayout-&gt;layoutState</code> (<code>parentInfo.add()</code> +<br />
<code>layoutInfo()-&gt;remove()</code>), which frees/replaces some <code>QLayoutItem*</code>.</li>
<li>The drag's <code>savedState</code> snapshot <strong>shares those same <code>QLayoutItem*</code> pointers</strong> with<br />
<code>layoutState</code>, so it is now stale.</li>
<li>The nested <code>setFloating()</code> → <code>endDrag()</code> → <code>restore()</code> does <code>layoutState = savedState</code><br />
and walks it in <code>applyState()</code> → <code>QDockAreaLayoutInfo::reparentWidgets()</code>, where<br />
<code>item.widgetItem-&gt;widget()</code> dereferences a freed <code>widgetItem</code> → access violation<br />
(qdockarealayout.cpp ~line 2210). The <code>qobject_cast&lt;QDockWidgetGroupWindow*&gt;</code> skip<br />
that landed for QTBUG-118579 sits <em>after</em> that deref, so it doesn't help here.</li>
</ol>
<p dir="auto">It is not drag-specific: doing the 2→1 dissolution purely programmatically<br />
(<code>addDockWidget()</code> + <code>setFloating()</code> on a member of a 2-member group) crashes too, just<br />
deferred — confirming the fault is the group-window teardown replaying a stale snapshot.</p>
<h3>The fix</h3>
<p dir="auto">Drop the stale snapshot before the nested <code>setFloating()</code>, but <strong>only</strong> when this<br />
reparent actually dissolves the group (&lt; 2 members left) — so a normal tear where the<br />
group survives keeps its original <code>restore()</code> untouched:</p>
<pre><code class="language-cpp">// in QDockWidgetGroupWindow::reparentToMainWindow(), right before
// dockWidget-&gt;setFloating(wasFloating):
if (findChildren&lt;QDockWidget *&gt;(Qt::FindDirectChildrenOnly).size() &lt; 2)
    mwLayout-&gt;savedState.clear();
</code></pre>
<p dir="auto"><code>QMainWindowLayoutState::clear()</code> only resets the structure (<code>item_list.clear()</code>); it<br />
does <strong>not</strong> delete the shared <code>QLayoutItem</code>s, so <code>layoutState</code> (already updated by hand<br />
above) stays valid, and the nested <code>restore()</code> early-returns because <code>savedState</code> is now<br />
invalid. (An <em>unconditional</em> <code>mwLayout-&gt;savedState.clear();</code> also fixes the crash, but it<br />
changes the surviving-tear path too and adds a needless repaint on it — hence the guard.)</p>
<p dir="auto">Build a patched qtbase (or just QtWidgets) and link against it. Verified on<br />
<strong>Windows 11, Qt 6.11.1, MSVC x64</strong>: the 2→1 tear no longer crashes; create / move /<br />
3→2 are unaffected. (A brief repaint flash on tear is inherent Qt reparent behaviour,<br />
present with or without the patch.)</p>
<h3>For maintainers</h3>
<p dir="auto">This is a local workaround; the cleaner upstream fix is probably to stop <code>restore()</code><br />
from replaying a <code>savedState</code> that <code>reparentToMainWindow()</code> has just invalidated — e.g.<br />
keep <code>savedState</code> consistent across the dissolution, or skip the nested<br />
restore/reparentWidgets when the group is being torn down. Happy to help test a proper<br />
patch. This looks like a Windows regression/uncovered case of the QTBUG-118579 family<br />
(fixed for Linux/X11 + macOS in 6.5.4 / 6.6.2 / 6.7.0).</p>
]]></description><link>https://forum.qt.io/post/838824</link><guid isPermaLink="true">https://forum.qt.io/post/838824</guid><dc:creator><![CDATA[jvenema]]></dc:creator><pubDate>Fri, 19 Jun 2026 12:08:45 GMT</pubDate></item><item><title><![CDATA[Reply to Crash tearing 2nd-to-last dock out of a floating tabbed group (QDockWidgetGroupWindow) — Windows, Qt 6.11.1 on Fri, 19 Jun 2026 11:30:50 GMT]]></title><description><![CDATA[<p dir="auto">This is most likely fixed in Qt6.11.2 and Qt6.12</p>
]]></description><link>https://forum.qt.io/post/838823</link><guid isPermaLink="true">https://forum.qt.io/post/838823</guid><dc:creator><![CDATA[Christian Ehrlicher]]></dc:creator><pubDate>Fri, 19 Jun 2026 11:30:50 GMT</pubDate></item></channel></rss>