Tk Source Code

View Ticket
Login
2025-02-22
10:48 Ticket [194c0b8650] revised_text branch / tableList demo crash status still Open with 3 other changes artifact: 1a7ec170e1 user: fvogel
2025-02-02
08:29 Ticket [ad458a3a72] Sections consistency assertion fails when switching -elide in the revised text widget status still Open with 4 other changes artifact: 8b571b813a user: fvogel
2025-01-28
20:53 Ticket [bdd1f64523] Assertion failed when switching -elide in the revised text widget status still Open with 5 other changes artifact: b617c06ce7 user: fvogel
2025-01-12
14:42 Ticket [73d8d94916] tablelist widget displaying a tree structure crashes when run with revised_text status still Open with 3 other changes artifact: 1840a77546 user: fvogel
2024-11-20
20:29 Ticket [73d8d94916]: 3 changes artifact: bda84e7520 user: fvogel
2024-11-17
22:23 Ticket [73d8d94916]: 3 changes artifact: e43c885093 user: fvogel
22:20 Ticket [73d8d94916]: 3 changes artifact: 2c17ebc1ee user: fvogel
2024-11-16
22:39 Ticket [73d8d94916]: 3 changes artifact: 36aebe158e user: fvogel
17:55 Closed ticket [24d6449976]: Tablelist crash with revised_text plus 6 other changes artifact: 0a0df70185 user: fvogel
14:33 New ticket [73d8d94916] tablelist widget displaying a tree structure crashes when run with revised_text. artifact: 3406c03406 user: nemethi

Ticket UUID: 73d8d949162ab02056a4ea0ff680b093c8ca6fae
Title: tablelist widget displaying a tree structure crashes when run with revised_text
Type: Bug Version: revised_text
Submitter: nemethi Created on: 2024-11-16 14:33:22
Subsystem: 18. [text] Assigned To: nobody
Priority: 5 Medium Severity: Severe
Status: Open Last Modified: 2025-01-12 14:42:23
Resolution: None Closed By: nobody
    Closed on:
Description:

I have experienced the following crash when using Tablelist with Tk built from the revised_text branch or Tk with the rtext extension:

The script dirViewer.tcl in the Tablelist demos directory crashes reliably on all platforms with segmentation fault by executing the following steps:

  • Expand the "//zipfs:/" node.
  • Expand the "lib" node.
  • Expand the "tcl" node.
  • Expand the "tcl_library" node.
  • Collapse the "tcl_library" node.
  • Expand the "tcl_library" node again.
  • Collapse the "tcl_library" node again.

The download location of Tablelist is

https://www.nemethi.de

User Comments: fvogel added on 2025-01-12 14:42:23:

Asan on macOS with Xquartz spits:

% =================================================================
==2488==ERROR: AddressSanitizer: heap-use-after-free on address 0x60c002699538 at pc 0x00010d244a1e bp 0x7ff7b52f9500 sp 0x7ff7b52f94f8
READ of size 8 at 0x60c002699538 thread T0
    #0 0x10d244a1d in TkTextIndexSetSegment tkTextIndex.c:458
    #1 0x10d14b728 in LayoutDLine tkTextDisp.c:4492
    #2 0x10d12f07f in UpdateDisplayInfo tkTextDisp.c:5541
    #3 0x10d18a707 in TkTextIndexBbox tkTextDisp.c:12443
    #4 0x10d2b15bf in TkTextGetCursorBbox tkTextMark.c:2578
    #5 0x10cf1d857 in TextBlinkProc tkText.c:6169
    #6 0x10cf0eefa in TkConfigureText tkText.c:4346
    #7 0x10cf4c120 in TextWidgetObjCmd tkText.c:1663
    #8 0x10e156527 in Dispatch tclBasic.c:4640
    #9 0x10e13906a in TclNRRunCallbacks tclBasic.c:4656
    #10 0x10e1374d5 in Tcl_EvalObjv tclBasic.c:4395
    #11 0x10e144d07 in TclEvalEx tclBasic.c:5495
    #12 0x10e13dde3 in Tcl_EvalEx tclBasic.c:5146
    #13 0x10c65ea98 in Tk_BindEvent tkBind.c:2582
    #14 0x10c6d5fdb in TkBindEventProc tkCmds.c:320
    #15 0x10c75f13b in Tk_HandleEvent tkEvent.c:1276
    #16 0x10c7683f2 in WindowEventProc tkEvent.c:1707
    #17 0x10ebc689f in Tcl_ServiceEvent tclNotify.c:725
    #18 0x10ebc87d4 in Tcl_DoOneEvent tclNotify.c:960
    #19 0x10c76c735 in Tk_MainLoop tkEvent.c:2093
    #20 0x10c863228 in Tk_MainEx tkMain.c:378
    #21 0x10abfcc2a in main tkAppInit.c:115
    #22 0x7ff80bd342cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)

0x60c002699538 is located 56 bytes inside of 121-byte region [0x60c002699500,0x60c002699579)
freed by thread T0 here:
    #0 0x10b564956 in free+0xa6 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdd956)
    #1 0x10e0c71ec in TclpFree tclAlloc.c:724
    #2 0x10e1b5b09 in Tcl_DbCkfree tclCkalloc.c:641
    #3 0x10d016299 in TkBTreeFreeSegment tkTextBTree.c:6057
    #4 0x10d03d746 in UpdateElideInfo tkTextBTree.c:8945
    #5 0x10d05a722 in TkBTreeTag tkTextBTree.c:9824
    #6 0x10d2cc8c2 in TagAddRemove tkTextTag.c:1672
    #7 0x10d2bdad4 in TkTextTagCmd tkTextTag.c:330
    #8 0x10cf5df7d in TextWidgetObjCmd tkText.c:2600
    #9 0x10e156527 in Dispatch tclBasic.c:4640
    #10 0x10e13906a in TclNRRunCallbacks tclBasic.c:4656
    #11 0x10e1374d5 in Tcl_EvalObjv tclBasic.c:4395
    #12 0x10e144d07 in TclEvalEx tclBasic.c:5495
    #13 0x10e13dde3 in Tcl_EvalEx tclBasic.c:5146
    #14 0x10c65ea98 in Tk_BindEvent tkBind.c:2582
    #15 0x10c6d5fdb in TkBindEventProc tkCmds.c:320
    #16 0x10c75f13b in Tk_HandleEvent tkEvent.c:1276
    #17 0x10c7683f2 in WindowEventProc tkEvent.c:1707
    #18 0x10ebc689f in Tcl_ServiceEvent tclNotify.c:725
    #19 0x10ebc87d4 in Tcl_DoOneEvent tclNotify.c:960
    #20 0x10c76c735 in Tk_MainLoop tkEvent.c:2093
    #21 0x10c863228 in Tk_MainEx tkMain.c:378
    #22 0x10abfcc2a in main tkAppInit.c:115
    #23 0x7ff80bd342cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)

previously allocated by thread T0 here:
    #0 0x10b56480d in malloc+0x9d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdd80d)
    #1 0x10e0c71bc in TclpAlloc tclAlloc.c:700
    #2 0x10e1b370e in Tcl_DbCkalloc tclCkalloc.c:398
    #3 0x10d0b0c3d in MakeSegment tkTextBTree.c:1189
    #4 0x10d0b0e6e in MakeLink tkTextBTree.c:1200
    #5 0x10d03c544 in UpdateElideInfo tkTextBTree.c:8870
    #6 0x10d05a722 in TkBTreeTag tkTextBTree.c:9824
    #7 0x10d2cc8c2 in TagAddRemove tkTextTag.c:1672
    #8 0x10d2bdad4 in TkTextTagCmd tkTextTag.c:330
    #9 0x10cf5df7d in TextWidgetObjCmd tkText.c:2600
    #10 0x10e156527 in Dispatch tclBasic.c:4640
    #11 0x10e13906a in TclNRRunCallbacks tclBasic.c:4656
    #12 0x10e1374d5 in Tcl_EvalObjv tclBasic.c:4395
    #13 0x10e144d07 in TclEvalEx tclBasic.c:5495
    #14 0x10e13dde3 in Tcl_EvalEx tclBasic.c:5146
    #15 0x10c65ea98 in Tk_BindEvent tkBind.c:2582
    #16 0x10c6d5fdb in TkBindEventProc tkCmds.c:320
    #17 0x10c75f13b in Tk_HandleEvent tkEvent.c:1276
    #18 0x10c7683f2 in WindowEventProc tkEvent.c:1707
    #19 0x10ebc689f in Tcl_ServiceEvent tclNotify.c:725
    #20 0x10ebc87d4 in Tcl_DoOneEvent tclNotify.c:960
    #21 0x10c76c735 in Tk_MainLoop tkEvent.c:2093
    #22 0x10c863228 in Tk_MainEx tkMain.c:378
    #23 0x10abfcc2a in main tkAppInit.c:115
    #24 0x7ff80bd342cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)

SUMMARY: AddressSanitizer: heap-use-after-free tkTextIndex.c:458 in TkTextIndexSetSegment
Shadow bytes around the buggy address:
  0x60c002699280: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x60c002699300: 00 00 00 00 00 00 01 fa fa fa fa fa fa fa fa fa
  0x60c002699380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 fa
  0x60c002699400: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x60c002699480: 00 00 00 00 00 00 01 fa fa fa fa fa fa fa fa fa
=>0x60c002699500: fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd
  0x60c002699580: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x60c002699600: fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa fa
  0x60c002699680: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 fa
  0x60c002699700: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x60c002699780: 00 00 00 00 00 00 00 01 fa fa fa fa fa fa 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
==2488==ABORTING
Abort trap: 6

So the text widget accesses memory that got previously freed.

A small test case would help a lot...


fvogel added on 2024-11-20 20:29:28:

Building with:

  int tkBTreeDebug = 1;
then running script dirViewer.tcl and performing the expand/collapse operations triggers a panic: BranchCheckProc: connection is not linked. This is interesting because it happens before the reported crash.

This panic triggers during execution of:

  .tf.tbl.body tag add elidedRow 18.0 18.end+1indices


fvogel added on 2024-11-17 22:23:30:

On Linux Debian, the stack trace is a bit different, since instead of an access violation it is now a plain assertion failed in CheckLine() because linePtr is NULL:

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff7b67537 in __GI_abort () at abort.c:79
#2  0x00007ffff7b6740f in __assert_fail_base (fmt=0x7ffff7cde688 "%s%s%s:%u: %s%sAssertion `%s' failed.\n%n", assertion=0x7ffff6dc8500 "linePtr", 
    file=0x7ffff6dc84b0 "/home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextIndex.c", line=127, function=<optimized out>) at assert.c:92
#3  0x00007ffff7b766d2 in __GI___assert_fail (assertion=0x7ffff6dc8500 "linePtr", file=0x7ffff6dc84b0 "/home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextIndex.c", line=127, 
    function=0x7ffff6dc91e8 <__PRETTY_FUNCTION__.49> "CheckLine") at assert.c:101
#4  0x00007ffff6d27840 in CheckLine (indexPtr=0x7fffffffc738, linePtr=0x0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextIndex.c:127
#5  0x00007ffff6d2856b in TkTextIndexSetSegment (indexPtr=0x7fffffffc738, segPtr=0x55555648a8f0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextIndex.c:460
#6  0x00007ffff6d1020b in LayoutDLine (indexPtr=0x7fffffffc980, displayLineNo=0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextDisp.c:4494
#7  0x00007ffff6d126a4 in UpdateDisplayInfo (textPtr=0x555555a466b0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextDisp.c:5543
#8  0x00007ffff6d21189 in TkTextIndexBbox (textPtr=0x555555a466b0, indexPtr=0x7fffffffcb40, extents=0, xPtr=0x7fffffffcbbc, yPtr=0x7fffffffcbb8, widthPtr=0x7fffffffcbb4, heightPtr=0x7fffffffcbb0, 
    charWidthPtr=0x7fffffffcb38, thisChar=0x7fffffffcb3c) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextDisp.c:12446
#9  0x00007ffff6d37135 in TkTextGetCursorBbox (textPtr=0x555555a466b0, x=0x7fffffffcbbc, y=0x7fffffffcbb8, w=0x7fffffffcbb4, h=0x7fffffffcbb0)
    at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkTextMark.c:2578
#10 0x00007ffff6cd5818 in TextBlinkProc (clientData=0x555555a466b0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkText.c:6169
#11 0x00007ffff6cd1b6c in TkConfigureText (interp=0x555555574100, textPtr=0x555555a466b0, objc=2, objv=0x5555555794e0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkText.c:4346
#12 0x00007ffff6cc9669 in TextWidgetObjCmd (clientData=0x555555a466b0, interp=0x555555574100, objc=4, objv=0x5555555794d0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkText.c:1663
#13 0x00007ffff7d8dcd5 in Dispatch (data=0x5555564b4bb8, interp=0x555555574100, dummy4602=0) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclBasic.c:4640
#14 0x00007ffff7d8dd3c in TclNRRunCallbacks (interp=0x555555574100, result=0, rootPtr=0x0) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclBasic.c:4656
#15 0x00007ffff7d8d46e in Tcl_EvalObjv (interp=0x555555574100, objc=3, objv=0x555555578490, flags=2097168) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclBasic.c:4395
#16 0x00007ffff7d8ff70 in TclEvalEx (interp=0x555555574100, 
    script=0x555556484860 "\n\tif {[winfo exists .tf.tbl.body.ind_k5,0]} {\n\t    foreach {tablelist::W tablelist::x tablelist::y}  [tablelist::convEventFields .tf.tbl.body.ind_k5,0 64 5] {}\n\t    if {$tablelist::y < [winfo y [$tabl"..., numBytes=1206, flags=131072, line=2, clNextOuter=0x0, 
    outerScript=0x555556484860 "\n\tif {[winfo exists .tf.tbl.body.ind_k5,0]} {\n\t    foreach {tablelist::W tablelist::x tablelist::y}  [tablelist::convEventFields .tf.tbl.body.ind_k5,0 64 5] {}\n\t    if {$tablelist::y < [winfo y [$tabl"...) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclBasic.c:5495
#17 0x00007ffff7d8f10b in Tcl_EvalEx (interp=0x555555574100, script=0x555556484860 "\n\tif {[winfo exists .tf.tbl.body.ind_k5,0]} {\n\t    foreach {tablelist::W tablelist::x tablelist::y}  [tablelist::convEventFields .tf.tbl.body.ind_k5,0 64 5] {}\n\t    if {$tablelist::y < [winfo y [$tabl"..., numBytes=1206, flags=131072) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclBasic.c:5146
#18 0x00007ffff6be4240 in Tk_BindEvent (bindPtr=0x555555717bd0, eventPtr=0x55555649aec0, tkwin=0x55555632e660, numObjects=5, objArr=0x7fffffffdaf0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkBind.c:2611
#19 0x00007ffff6bf216c in TkBindEventProc (winPtr=0x55555632e660, eventPtr=0x55555649aec0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkCmds.c:320
#20 0x00007ffff6c000b6 in Tk_HandleEvent (eventPtr=0x55555649aec0) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkEvent.c:1310
#21 0x00007ffff6c00a7b in WindowEventProc (evPtr=0x55555649aeb0, flags=-3) at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkEvent.c:1741
#22 0x00007ffff7ecbc50 in Tcl_ServiceEvent (flags=-3) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclNotify.c:710
#23 0x00007ffff7ecbf4c in Tcl_DoOneEvent (flags=-3) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclNotify.c:943
#24 0x00007ffff6c010c2 in Tk_MainLoop () at /home/francois/Documents/tcltk/fossil/tk/unix/../generic/tkEvent.c:2127
#25 0x00007ffff7ec3d9c in Tcl_MainEx (argc=-1, argv=0x7fffffffdf88, appInitProc=0x5555555551d4 <Tcl_AppInit>, interp=0x555555574100) at /home/francois/Documents/tcltk/fossil/tcl/generic/tclMain.c:593
#26 0x00005555555551d4 in main (argc=2, argv=0x7fffffffdf88) at /home/francois/Documents/tcltk/fossil/tcl/unix/tclAppInit.c:94


fvogel added on 2024-11-17 22:20:17:

A start of a debug session on Windows:

The crash happens during execution of a bound script starting with:

"\n\tif {[winfo exists .tf.tbl.body.ind_k8,0]} {\n\t    foreach {tablelist::W tablelist::x tablelist::y}  [tablelist::convEventFields .tf.tbl.body.ind_k8,0 31 1] {}\n\t    if {$tablelist::y < [winfo y [$tabl...

It triggers because the linePtr received by TkBTreeLinesTo has a value like 0xffffffff00000003, which is not supposed to happen.

This unexpected value of the linePtr is returned (in segPtr->sectionPtr->linePtr) by:

	segPtr = TkBTreeFindEndOfElidedRange(textPtr->sharedTextPtr, textPtr, segPtr);

in LayoutDLine() at line 4495 of tkTextDisp.c.

In TkBTreeFindEndOfElidedRange(), the number of "Links" segments of the line pointer (segPtr->sectionPtr->linePtr->numLinks) is zero. Consequently, the link segment (which marks the end of the elided range we're searching for) is searched by looking at the "Branch" segment (which marks the beginning of the elided range), and then getting the link segment pointed to by the branch segment. This happens here.

In FindBranchSegment(), the branch segment is found (linePtr->numBranches is 1) by SearchBranchInLine() and returned. That branch segment has value 0xffffffff00000003 in branchPtr->body.branch.nextPtr->sectionPtr->linePtr.

I'm not seeing anything suspect in SearchBranchInLine(). The sectionPtr first is segPtr->sectionPtr, and then the for loop returns sectionPtr->segPtr->prevPtr during its first iteration because the branch segment is immediately found.

From where this interesting 0xffffffff00000003 value does come remains an unsolved question.


fvogel added on 2024-11-16 22:39:16:

Backtrace:

>	tcl9tk90.dll!TkBTreeLinesTo(TkTextBTree_ * tree, const TkText * textPtr, const TkTextLine * linePtr, int * deviation) Ligne 8046	C
 	tcl9tk90.dll!CheckLine(const TkTextIndex * indexPtr, const TkTextLine * linePtr) Ligne 149	C
 	tcl9tk90.dll!TkTextIndexSetSegment(TkTextIndex * indexPtr, TkTextSegment * segPtr) Ligne 460	C
 	tcl9tk90.dll!LayoutDLine(const TkTextIndex * indexPtr, unsigned int displayLineNo) Ligne 4495	C
 	tcl9tk90.dll!UpdateDisplayInfo(TkText * textPtr) Ligne 5543	C
 	tcl9tk90.dll!TkTextIndexBbox(TkText * textPtr, const TkTextIndex * indexPtr, int extents, int * xPtr, int * yPtr, int * widthPtr, int * heightPtr, int * charWidthPtr, int * thisChar) Ligne 12442	C
 	tcl9tk90.dll!TkTextGetCursorBbox(TkText * textPtr, int * x, int * y, int * w, int * h) Ligne 2578	C
 	tcl9tk90.dll!TextBlinkProc(void * clientData) Ligne 6169	C
 	tcl9tk90.dll!TkConfigureText(Tcl_Interp * interp, TkText * textPtr, int objc, Tcl_Obj * const * objv) Ligne 4346	C
 	tcl9tk90.dll!TextWidgetObjCmd(void * clientData, Tcl_Interp * interp, int objc, Tcl_Obj * const * objv) Ligne 1663	C
 	tcl90.dll!Dispatch(void * * data, Tcl_Interp * interp, int dummy4602) Ligne 4641	C
 	tcl90.dll!TclNRRunCallbacks(Tcl_Interp * interp, int result, NRE_callback * rootPtr) Ligne 4656	C
 	tcl90.dll!Tcl_EvalObjv(Tcl_Interp * interp, __int64 objc, Tcl_Obj * const * objv, int flags) Ligne 4396	C
 	tcl90.dll!TclEvalEx(Tcl_Interp * interp, const char * script, __int64 numBytes, int flags, __int64 line, __int64 * clNextOuter, const char * outerScript) Ligne 5495	C
 	tcl90.dll!Tcl_EvalEx(Tcl_Interp * interp, const char * script, __int64 numBytes, int flags) Ligne 5147	C
 	tcl9tk90.dll!Tk_BindEvent(Tk_BindingTable_ * bindPtr, _XEvent * eventPtr, Tk_Window_ * tkwin, __int64 numObjects, void * * objArr) Ligne 2611	C
 	tcl9tk90.dll!TkBindEventProc(TkWindow * winPtr, _XEvent * eventPtr) Ligne 322	C
 	tcl9tk90.dll!Tk_HandleEvent(_XEvent * eventPtr) Ligne 1310	C
 	tcl9tk90.dll!WindowEventProc(Tcl_Event * evPtr, int flags) Ligne 1742	C
 	tcl90.dll!Tcl_ServiceEvent(int flags) Ligne 710	C
 	tcl90.dll!Tcl_DoOneEvent(int flags) Ligne 1007	C
 	tcl9tk90.dll!Tk_MainLoop() Ligne 2127	C
 	tcl90.dll!Tcl_MainExW(__int64 argc, wchar_t * * argv, int(*)(Tcl_Interp *) appInitProc, Tcl_Interp * interp) Ligne 563	C
 	tclsh90.exe!wmain(int argc, wchar_t * * argv) Ligne 144	C