mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-08-05 20:54:13 +02:00
Fix stack-overflow crash in FileElementCollectionItem::setUpIcon()
The unconditional early return was narrowed to non-directories only, so that the just-added warning badge could be picked up once setUpData() resolved m_qet_directory_unreadable asynchronously. But every directory then called setIcon() on every single data(Qt::DecorationRole) query -- not just once -- and QStandardItem::setIcon() -> setData() emits dataChanged() unconditionally (QIcon has no equality check to suppress it). QTreeView handles dataChanged() by recomputing the row's size hint, which re-enters data() for the same index, calling setIcon() again: unbounded mutual recursion, confirmed by an isolated reproduction to overflow the stack in a single frame (100k+ frames) well before the first paint completes. Matches plc-user's report of a segfault right as the elements tree begins drawing. The race the guard was widened for doesn't actually occur: ElementsCollectionModel only attaches itself to the tree view (the only way data() becomes reachable) from loadingFinished(), which fires after the QtConcurrent::map over every item -- this one included -- has already finished. m_qet_directory_unreadable is therefore always final before setUpIcon() can run for the first time, so the plain, always-only- once guard is sufficient and the badge still works correctly.
This commit is contained in:
@@ -430,13 +430,20 @@ void FileElementCollectionItem::setUpData()
|
|||||||
*/
|
*/
|
||||||
void FileElementCollectionItem::setUpIcon()
|
void FileElementCollectionItem::setUpIcon()
|
||||||
{
|
{
|
||||||
// Directories are cheap to (re-)decide: no early return for them.
|
// Must return unconditionally once an icon is set: setIcon() calls
|
||||||
// setUpData() -- which resolves m_qet_directory_unreadable via
|
// setData(), which emits dataChanged() regardless of whether the new
|
||||||
// localName() -- runs asynchronously (QtConcurrent::map), so this can
|
// icon differs from the old one (QIcon has no meaningful equality).
|
||||||
// be called for a directory before that result is known; without
|
// QTreeView responds to dataChanged() by recomputing the row's size
|
||||||
// this, the plain folder icon would get cached by the guard below
|
// hint, which re-enters data() for this same index -- so without this
|
||||||
// and the warning badge would never appear for that item.
|
// guard, any repeated setIcon() here recurses until the stack
|
||||||
if (!isDir() && !icon().isNull())
|
// overflows. Confirmed by crash report on PR #633.
|
||||||
|
//
|
||||||
|
// This item's m_qet_directory_unreadable is already final by the time
|
||||||
|
// this can run at all: ElementsCollectionModel only attaches itself
|
||||||
|
// to the tree view (making data() reachable) from loadingFinished(),
|
||||||
|
// which fires after the QtConcurrent::map over every item -- this one
|
||||||
|
// included -- has completed. So there is no race to work around here.
|
||||||
|
if (!icon().isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (isCollectionRoot()) {
|
if (isCollectionRoot()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user