Bug 328263

Summary: KLineEdit with squeezed text enabled can cause endless loop
Product: [Unmaintained] kdelibs Reporter: Axel <arnolda747>
Component: kdeuiAssignee: kdelibs bugs <kdelibs-bugs>
Status: RESOLVED FIXED    
Severity: crash CC: cfeck, ThomasBleher
Priority: NOR    
Version: Git   
Target Milestone: ---   
Platform: MacPorts   
OS: macOS   
Latest Commit: Version Fixed In: 4.12.1
Sentry Crash Report:

Description Axel 2013-11-30 21:03:59 UTC
If KLineEdit has squeezed text enabled, but the widget has still zero width, KLineEdit::setSqueezedText() can go into an endless loop trying to remove letters from the string (line 622 - 627 of the git version).  This endless loop causes for example digikam 3.5.0 on a Mac to freeze at startup, when the widget is not yet mapped and therefore still has zero width. However, this problem is not digikam specific, it can be reproduced by any code creating a zero width KLineEdit.

Adding an additional check for (letters > 0) fixes the problem. There is a similar loop just above, where a check for not overrunning the end of the string might be safe to add as well, although I have not encountered an overrun there.

Reproducible: Always

Steps to Reproduce:
Start digikam 3.5.0 on a Mac
Actual Results:  
digikam freezes when setting the initial status message

Expected Results:  
digikam should start
Comment 1 Christoph Feck 2013-12-05 23:24:17 UTC
Thanks for the analysis. Would you like to propose a patch and post it to https://reviewboard.kde.org/ ?
Comment 2 Thomas Bleher 2013-12-16 06:47:58 UTC
I can easily reproduce this bug on Ubuntu 13.10 (amd64) with digikam 4:3.4.0-1ubuntu3 and kdelibs 4:4.11.2-0ubuntu2.1.

Backtrace from gdb looks as follows:
#0  GPOS_Do_Glyph_Lookup (gpi=gpi@entry=0x7fffc3adf3d0, lookup_index=lookup_index@entry=3, buffer=buffer@entry=0x1907120, context_length=context_length@entry=65535, nesting_level=1, 
    nesting_level@entry=0) at ../3rdparty/harfbuzz/src/harfbuzz-gpos.c:5803
#1  0x00007f00563ead9f in GPOS_Do_String_Lookup (buffer=0x1907120, lookup_index=3, gpi=0x7fffc3adf3d0) at ../3rdparty/harfbuzz/src/harfbuzz-gpos.c:5905
#2  HB_GPOS_Apply_String (font=<optimized out>, gpos=0x18e7860, load_flags=<optimized out>, buffer=0x1907120, dvi=<optimized out>, r2l=<optimized out>)
    at ../3rdparty/harfbuzz/src/harfbuzz-gpos.c:6076
#3  0x00007f00563efb52 in HB_OpenTypePosition (item=0x7fffc3adf660, availableGlyphs=41, doLogClusters=<optimized out>) at ../3rdparty/harfbuzz/src/harfbuzz-shaper.cpp:1265
#4  0x00007f00563f4a13 in HB_ShapeItem (shaper_item=0x7fffc3adf660) at ../3rdparty/harfbuzz/src/harfbuzz-shaper.cpp:1419
#5  0x00007f00570bcd58 in QTextEngine::shapeTextWithHarfbuzz (this=this@entry=0x7fffc3adfea0, item=item@entry=0) at text/qtextengine.cpp:1342
#6  0x00007f00570bd6e2 in QTextEngine::shapeText (this=this@entry=0x7fffc3adfea0, item=item@entry=0) at text/qtextengine.cpp:935
#7  0x00007f00570bda05 in QTextEngine::shape (this=this@entry=0x7fffc3adfea0, item=item@entry=0) at text/qtextengine.cpp:1450
#8  0x00007f00570c183f in QTextEngine::width (this=this@entry=0x7fffc3adfea0, from=from@entry=0, len=len@entry=41) at text/qtextengine.cpp:1690
#9  0x00007f005709a150 in QFontMetrics::width (this=this@entry=0x7fffc3ae30a0, text=..., len=41, len@entry=-1, flags=flags@entry=0) at text/qfontmetrics.cpp:582
#10 0x00007f005709a477 in QFontMetrics::width (this=this@entry=0x7fffc3ae30a0, text=..., len=len@entry=-1) at text/qfontmetrics.cpp:546
#11 0x00007f0057c24e21 in KLineEdit::setSqueezedText (this=this@entry=0x193c6b0) at ../../kdeui/widgets/klineedit.cpp:626
#12 0x00007f0057c28123 in KLineEdit::resizeEvent (this=0x193c6b0, ev=0x7fffc3ae3580) at ../../kdeui/widgets/klineedit.cpp:694
#13 0x00007f0056ec10d2 in QWidget::event (this=this@entry=0x193c6b0, event=event@entry=0x7fffc3ae3580) at kernel/qwidget.cpp:8540
#14 0x00007f0057272931 in QLineEdit::event (this=this@entry=0x193c6b0, e=e@entry=0x7fffc3ae3580) at widgets/qlineedit.cpp:1524
#15 0x00007f0057c2a8c0 in KLineEdit::event (this=0x193c6b0, ev=0x7fffc3ae3580) at ../../kdeui/widgets/klineedit.cpp:1401
#16 0x00007f0056e71dfc in QApplicationPrivate::notify_helper (this=this@entry=0x167f580, receiver=receiver@entry=0x193c6b0, e=e@entry=0x7fffc3ae3580) at kernel/qapplication.cpp:4567
#17 0x00007f0056e78470 in QApplication::notify (this=this@entry=0x7fffc3ae44e0, receiver=receiver@entry=0x193c6b0, e=e@entry=0x7fffc3ae3580) at kernel/qapplication.cpp:4353
#18 0x00007f0057b7ba6a in KApplication::notify (this=0x7fffc3ae44e0, receiver=0x193c6b0, event=0x7fffc3ae3580) at ../../kdeui/kernel/kapplication.cpp:311
#19 0x00007f00564808bd in QCoreApplication::notifyInternal (this=0x7fffc3ae44e0, receiver=receiver@entry=0x193c6b0, event=event@entry=0x7fffc3ae3580) at kernel/qcoreapplication.cpp:946
#20 0x00007f0056ebd0f1 in sendEvent (event=0x7fffc3ae3580, receiver=0x193c6b0) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:231
#21 QWidgetPrivate::sendPendingMoveAndResizeEvents (this=0x3fa7290, recursive=recursive@entry=true, disableUpdates=<optimized out>, disableUpdates@entry=true) at kernel/qwidget.cpp:7445
#22 0x00007f0056ebd046 in QWidgetPrivate::sendPendingMoveAndResizeEvents (this=0x1917d90, recursive=recursive@entry=true, disableUpdates=<optimized out>, disableUpdates@entry=true)
    at kernel/qwidget.cpp:7457
#23 0x00007f0056ebd046 in QWidgetPrivate::sendPendingMoveAndResizeEvents (this=0x3832f70, recursive=recursive@entry=true, disableUpdates=<optimized out>, disableUpdates@entry=true)
    at kernel/qwidget.cpp:7457
#24 0x00007f0056ebd046 in QWidgetPrivate::sendPendingMoveAndResizeEvents (this=0x18c1e50, recursive=recursive@entry=true, disableUpdates=<optimized out>, disableUpdates@entry=true)
    at kernel/qwidget.cpp:7457
#25 0x00007f0056ebeb0a in QWidgetPrivate::prepareToRender (this=this@entry=0x2956730, region=..., renderFlags=...) at kernel/qwidget.cpp:5403
#26 0x00007f0056ebfb05 in QWidgetPrivate::render (this=0x2956730, target=0x7fffc3ae3900, targetOffset=..., sourceRegion=..., renderFlags=..., readyToRender=readyToRender@entry=false)
    at kernel/qwidget.cpp:5667
#27 0x00007f0056ebfef9 in QWidget::render (this=<optimized out>, target=<optimized out>, targetOffset=..., sourceRegion=..., renderFlags=...) at kernel/qwidget.cpp:5186
#28 0x00007f0037511824 in ?? () from /usr/lib/kde4/plugins/styles/oxygen.so
#29 0x00007f0037511c07 in ?? () from /usr/lib/kde4/plugins/styles/oxygen.so
#30 0x00007f003750df6d in ?? () from /usr/lib/kde4/plugins/styles/oxygen.so
#31 0x00007f0056498be1 in QObject::event (this=0x39e2450, e=<optimized out>) at kernel/qobject.cpp:1156
#32 0x00007f0056e71dfc in QApplicationPrivate::notify_helper (this=this@entry=0x167f580, receiver=receiver@entry=0x39e2450, e=e@entry=0x7fffc3ae3d40) at kernel/qapplication.cpp:4567
#33 0x00007f0056e78470 in QApplication::notify (this=this@entry=0x7fffc3ae44e0, receiver=receiver@entry=0x39e2450, e=e@entry=0x7fffc3ae3d40) at kernel/qapplication.cpp:4353
#34 0x00007f0057b7ba6a in KApplication::notify (this=0x7fffc3ae44e0, receiver=0x39e2450, event=0x7fffc3ae3d40) at ../../kdeui/kernel/kapplication.cpp:311
#35 0x00007f00564808bd in QCoreApplication::notifyInternal (this=0x7fffc3ae44e0, receiver=0x39e2450, event=0x7fffc3ae3d40) at kernel/qcoreapplication.cpp:946
#36 0x00007f00564b0403 in sendEvent (event=<optimized out>, receiver=<optimized out>) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:231
#37 QTimerInfoList::activateTimers (this=0x167cd40) at kernel/qeventdispatcher_unix.cpp:622
#38 0x00007f00564ad7a1 in timerSourceDispatch (source=<optimized out>) at kernel/qeventdispatcher_glib.cpp:186
#39 0x00007f004debe3b6 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#40 0x00007f004debe708 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#41 0x00007f004debe7ac in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#42 0x00007f00564ada55 in QEventDispatcherGlib::processEvents (this=0x15b8ad0, flags=...) at kernel/qeventdispatcher_glib.cpp:424
#43 0x00007f0056f139d6 in QGuiEventDispatcherGlib::processEvents (this=<optimized out>, flags=...) at kernel/qguieventdispatcher_glib.cpp:204
#44 0x00007f005647f5ef in QEventLoop::processEvents (this=this@entry=0x7fffc3ae3fc0, flags=...) at kernel/qeventloop.cpp:149
#45 0x00007f005647f8e5 in QEventLoop::exec (this=this@entry=0x7fffc3ae3fc0, flags=...) at kernel/qeventloop.cpp:204
#46 0x00007f0056484e5b in QCoreApplication::exec () at kernel/qcoreapplication.cpp:1218
#47 0x00007f0056e7034c in QApplication::exec () at kernel/qapplication.cpp:3828
#48 0x0000000000491ef3 in main (argc=<optimized out>, argv=<optimized out>) at /build/buildd/digikam-3.4.0/core/digikam/main/main.cpp:235

The endless loop happens at line #11 (confirmed by stepping through the code with gdb using the "finish" command).
On my system, the bug happens everytime I try to search for tags in digikam (in the right side tag view).
Comment 3 Axel 2013-12-17 15:16:29 UTC
(In reply to comment #1)
> Thanks for the analysis. Would you like to propose a patch and post it to
> https://reviewboard.kde.org/ ?

Done! The patch actually also fixes a corresponding problem in the loop for too wide labels.
Comment 4 David Faure 2013-12-21 00:31:37 UTC
Git commit 9dc18abf5387ef40f6ddff02ef6b5407e70eefe0 by David Faure, on behalf of Axel Arnold.
Committed on 21/12/2013 at 00:31.
Pushed by dfaure into branch 'KDE/4.12'.

fix endless loop in KLineEdit->setSqueezedText()

If KLineEdit has squeezed text enabled, but the widget has still zero width, KLineEdit::setSqueezedText() can go into an endless loop trying to remove more than all letters from the string. This patch fixes both this underrun and the corresponding possible overrun if the squeezed text is too small. The underrun is responsible for endless loops in digikam, see the corresponding bug report.

REVIEW: 114519

M  +3    -2    kdeui/widgets/klineedit.cpp

http://commits.kde.org/kdelibs/9dc18abf5387ef40f6ddff02ef6b5407e70eefe0
Comment 5 David Faure 2013-12-21 00:34:28 UTC
Git commit ed9aa998c439a086ed82b925dc4bfcbf009cdcf2 by David Faure, on behalf of Axel Arnold.
Committed on 21/12/2013 at 00:34.
Pushed by dfaure into branch 'master'.

fix endless loop in KLineEdit->setSqueezedText()

If KLineEdit has squeezed text enabled, but the widget has still zero width, KLineEdit::setSqueezedText() can go into an endless loop trying to remove more than all letters from the string. This patch fixes both this underrun and the corresponding possible overrun if the squeezed text is too small. The underrun is responsible for endless loops in digikam, see the corresponding bug report.

REVIEW: 114519

M  +3    -2    src/klineedit.cpp

http://commits.kde.org/kcompletion/ed9aa998c439a086ed82b925dc4bfcbf009cdcf2
Comment 6 Christoph Feck 2013-12-21 01:35:39 UTC
Thanks for your contribution, Axel.