wallpapers/image: fix heap-use-after-free in SlideFilterModel::invalidate()
Original commit message(s)
- wallpapers/image: fix heap-use-after-free in SlideFilterModel::invalidate()
The sortCallback lambda already performs QSortFilterProxyModel::invalidate() followed by sort(0) whenever m_SortingMode changes. Calling sort(0) again inside SlideFilterModel::invalidate() caused a re-entrant invalidate()/sort() cycle, leaving m_randomOrder in an inconsistent state and triggering ASan heap-use-after-free in lessThan() when accessing the freed QArrayData.
Remove the redundant sort(0) from invalidate() to break the re-entrancy and let Qt schedule the sort as part of the normal invalidate() path.
Reason for the change
47/90 Test #47: testslidefiltermodel ....................***Failed 2.94 sec
********* Start testing of SlideFilterModelTest *********
Config: Using QtTest library 6.11.1, Qt 6.11.1 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 15.2.1 20260202), opensuse-tumbleweed 20260531
PASS : SlideFilterModelTest::initTestCase()
PASS : SlideFilterModelTest::testSlideFilterModelSortingOrder(Alphabetical 0)
PASS : SlideFilterModelTest::testSlideFilterModelSortingOrder(Alphabetical 1)
=================================================================
==24135==ERROR: AddressSanitizer: heap-use-after-free on address 0x7bb01822c340 at pc 0x7f803392953f bp 0x7ffd02258060 sp 0x7ffd02257820
READ of size 4 at 0x7bb01822c340 thread T0
#0 0x7f803392953e in memmove (/lib64/libasan.so.8+0x12953e) (BuildId: 88685a3f5f660d09752d9178981123dad8254596)
#1 0x7f802488e4d3 (/lib64/libQt6Core.so.6+0x48e4d3) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#2 0x7f8024877d4e (/lib64/libQt6Core.so.6+0x477d4e) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#3 0x7f8024881678 (/lib64/libQt6Core.so.6+0x481678) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#4 0x0000004cc9f7 in operator() /builds/plasma/plasma-workspace/wallpapers/image/plugin/slidefiltermodel.cpp:61
#5 0x0000004d667a in __invoke_impl<void, SlideFilterModel::SlideFilterModel(const QBindable<QSize>&, const QBindable<bool>&, const QBindable<SortingMode::Mode>&, const QBindable<bool>&, QObject*)::<lambda()>&> /usr/include/c++/15/bits/invoke.h:63
#6 0x0000004d61ea in __invoke_r<void, SlideFilterModel::SlideFilterModel(const QBindable<QSize>&, const QBindable<bool>&, const QBindable<SortingMode::Mode>&, const QBindable<bool>&, QObject*)::<lambda()>&> /usr/include/c++/15/bits/invoke.h:113
#7 0x0000004d5964 in _M_invoke /usr/include/c++/15/bits/std_function.h:292
#8 0x0000004ddb1b in std::function<void ()>::operator()() const /usr/include/c++/15/bits/std_function.h:593
#9 0x0000004d4115 in operator() /usr/include/qt6/QtCore/qproperty.h:343
#10 0x0000004d4161 in _FUN /usr/include/qt6/QtCore/qproperty.h:341
#11 0x7f80245d0bd9 (/lib64/libQt6Core.so.6+0x1d0bd9) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#12 0x7f802463e024 in QPropertyBindingPrivate::notifyNonRecursive() (/lib64/libQt6Core.so.6+0x23e024) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#13 0x7f802464b737 in QtPrivate::QPropertyBindingData::notifyObservers(QUntypedPropertyData*, QBindingStorage*) const (/lib64/libQt6Core.so.6+0x24b737) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#14 0x00000044351a in QProperty<SortingMode::Mode>::notify() (/builds/plasma/plasma-workspace/_build/bin/testslidefiltermodel+0x44351a) (BuildId: 3418eaeaab607c98d0468fde9e93757cf21f3106)
#15 0x000000440d1a in QProperty<SortingMode::Mode>::setValue(SortingMode::Mode) /usr/include/qt6/QtCore/qproperty.h:463
#16 0x00000043cd9f in QProperty<SortingMode::Mode>::operator=(SortingMode::Mode) /usr/include/qt6/QtCore/qproperty.h:474
#17 0x000000426612 in SlideFilterModelTest::testSlideFilterModelSortingOrder() /builds/plasma/plasma-workspace/wallpapers/image/plugin/autotests/test_slidefiltermodel.cpp:143
#18 0x00000042cea1 in SlideFilterModelTest::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) /builds/plasma/plasma-workspace/_build/wallpapers/image/plugin/autotests/testslidefiltermodel_autogen/include/test_slidefiltermodel.moc:103
#19 0x7f80245efa88 in QMetaMethodInvoker::invokeImpl(QMetaMethod, void*, Qt::ConnectionType, long long, void const* const*, char const* const*, QtPrivate::QMetaTypeInterface const* const*) (/lib64/libQt6Core.so.6+0x1efa88) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#20 0x7f80245f0bc6 in QMetaMethod::invokeImpl(QMetaMethod, void*, Qt::ConnectionType, long long, void const* const*, char const* const*, QtPrivate::QMetaTypeInterface const* const*) (/lib64/libQt6Core.so.6+0x1f0bc6) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
#21 0x7f803409389d (/lib64/libQt6Test.so.6+0x3089d) (BuildId: ae35bd550baa444c523864f879a7903b4582725d)
#22 0x7f80340959c4 (/lib64/libQt6Test.so.6+0x329c4) (BuildId: ae35bd550baa444c523864f879a7903b4582725d)
#23 0x7f80340a1e5a in QTest::qRun() (/lib64/libQt6Test.so.6+0x3ee5a) (BuildId: ae35bd550baa444c523864f879a7903b4582725d)
#24 0x7f80340a2bd1 in QTest::qExec(QObject*, int, char**) (/lib64/libQt6Test.so.6+0x3fbd1) (BuildId: ae35bd550baa444c523864f879a7903b4582725d)
#25 0x00000042cb8d in main /builds/plasma/plasma-workspace/wallpapers/image/plugin/autotests/test_slidefiltermodel.cpp:259
#26 0x7f8023c2b33d in __libc_start_call_main (/lib64/libc.so.6+0x2b33d) (BuildId: 5d3c9a4547c620ef2ebca457c75a3109c8e12203)
#27 0x7f8023c2b46a in __libc_start_main_alias_2 (/lib64/libc.so.6+0x2b46a) (BuildId: 5d3c9a4547c620ef2ebca457c75a3109c8e12203)
#28 0x00000041a874 in _start ../sysdeps/x86_64/start.S:115
0x7bb01822c340 is located 16 bytes inside of 28-byte region [0x7bb01822c330,0x7bb01822c34c)
freed by thread T0 here:
#0 0x7f803392b31f (/lib64/libasan.so.8+0x12b31f) (BuildId: 88685a3f5f660d09752d9178981123dad8254596)
#1 0x7f802471435b in QArrayData::reallocateUnaligned(QArrayData*, void*, long long, long long, QArrayData::AllocationOption) (/lib64/libQt6Core.so.6+0x31435b) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
previously allocated by thread T0 here:
#0 0x7f803392c01f in malloc (/lib64/libasan.so.8+0x12c01f) (BuildId: 88685a3f5f660d09752d9178981123dad8254596)
#1 0x7f8024713ec2 in QArrayData::allocate(QArrayData**, long long, long long, long long, QArrayData::AllocationOption) (/lib64/libQt6Core.so.6+0x313ec2) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
SUMMARY: AddressSanitizer: heap-use-after-free (/lib64/libQt6Core.so.6+0x48e4d3) (BuildId: 3223f3c6d419ed589f6536faeaf8886b8c6227f4)
Shadow bytes around the buggy address:
0x7bb01822c080: fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00
0x7bb01822c100: 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa
0x7bb01822c180: 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00
0x7bb01822c200: fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00
0x7bb01822c280: 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa
=>0x7bb01822c300: 00 00 00 00 fa fa fd fd[fd]fd fa fa 00 00 04 fa
0x7bb01822c380: fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00
0x7bb01822c400: 00 00 fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa
0x7bb01822c480: fd fd fd fa fa fa fd fd fd fd fa fa fd fd fd fa
0x7bb01822c500: fa fa fd fd fd fa fa fa fd fd fd fd fa fa fd fd
0x7bb01822c580: fd fd fa fa fd fd fd fa fa fa fd fd fd fd fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==24135==ABORTINGTest plan
Pass sliderfiltermodeltest
Screenshots or screen recordings
Bugs fixed
Found by Kilo Code with step-3.7-flash