From ad14eb17243a2397c8710b6894aeab53d125e3f3 Mon Sep 17 00:00:00 2001 From: Beat Hangartner Date: Tue, 6 Oct 2026 17:42:19 +0200 Subject: [PATCH] Delete the text items ElementPictureFactory::build() creates and drops parseText() creates a QGraphicsSimpleTextItem for every of an element (the DXF export reads them later) and appends it to the primitives it is given. build() draws every primitive twice, once for the normal and once for the low-zoom picture, and gave the second pass a fresh `primitives fake_prim` per primitive that went out of scope with its text items still allocated. dropCache() also removed a location's primitives without deleting their text items. LeakSanitizer on the Linux CI sanitizer build (separate PR) stops every --resave or export of a project whose elements have texts: ERROR: LeakSanitizer: detected memory leaks Indirect leak of 37200 byte(s) in 75 object(s) allocated from: #1 QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(QGraphicsItem*) #2 ElementPictureFactory::parseText(...) elementpicturefactory.cpp:658 #4 ElementPictureFactory::build(...) elementpicturefactory.cpp:324 Give the low-zoom pass one set of primitives for the whole element and delete its text items when both pictures are drawn; in dropCache(), take the primitives out of the hash and delete their text items. The items kept in m_primitives_H for the DXF export are unchanged, and the destructor deletes those as before. No file-format change, nothing drawn differently. Tests: the sanitizer job on Linux fails on master with the report above and passes with this change; ctest on macOS 64/64. The leak is invisible to a plain test and to ASan on macOS, which has no LeakSanitizer. Co-Authored-By: Claude Fable 5.1 Signed-off-by: Beat Hangartner --- sources/factory/elementpicturefactory.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sources/factory/elementpicturefactory.cpp b/sources/factory/elementpicturefactory.cpp index f0ad1e22d..2603d1bf5 100644 --- a/sources/factory/elementpicturefactory.cpp +++ b/sources/factory/elementpicturefactory.cpp @@ -114,7 +114,8 @@ void ElementPictureFactory::dropCache(const ElementsLocation &location) m_pictures_H.remove(uuid); m_low_pictures_H.remove(uuid); m_pixmap_H.remove(uuid); - m_primitives_H.remove(uuid); + //The text items belong to the cache; nothing else holds them. + qDeleteAll(m_primitives_H.take(uuid).m_texts); } /** @@ -249,6 +250,9 @@ bool ElementPictureFactory::build(const ElementsLocation &location, QPainter painter; QPicture pic; primitives primitives_; + //The low-zoom pass fills a second set of primitives that is only + //drawn, never kept: its text items are deleted at the end. + primitives low_primitives; if (picture) { painter.begin(picture); } @@ -320,8 +324,7 @@ bool ElementPictureFactory::build(const ElementsLocation &location, // complex font/text operations. } else { parseElement(qde, painter, primitives_); - primitives fake_prim; - parseElement(qde, low_painter, fake_prim); + parseElement(qde, low_painter, low_primitives); } } } @@ -330,6 +333,7 @@ bool ElementPictureFactory::build(const ElementsLocation &location, //End of the drawing painter.end(); low_painter.end(); + qDeleteAll(low_primitives.m_texts); const auto uuid_ = cacheKey(location); if (!picture) {