Ticket UUID: | 43573999cae70c8db2b7a234dd4ba0da63adb37a | |||
Title: | Problem with tkBind.c since Tk 8.6.10 (various assertions fail) | |||
Type: | Bug | Version: | 8.6.10 | |
Submitter: | robgcs | Created on: | 2022-09-27 14:20:08 | |
Subsystem: | 01. Bindings | Assigned To: | fvogel | |
Priority: | 5 Medium | Severity: | Critical | |
Status: | Closed | Last Modified: | 2022-10-26 19:42:16 | |
Resolution: | Fixed | Closed By: | fvogel | |
Closed on: | 2022-10-26 19:42:16 | |||
Description: |
Hello, everybody We have noticed that since Tk 8.6.10 our application crashes in connection with bindings. Different kinds of assertions fail in tkBind.c, for instance: tkBind.c:2825: MatchPatterns: Assertion `(psPtr->object == NULL) == (physPtrPtr != NULL)' tkBind.c:2489: Tk_BindEvent: Assertion `i + 1 < psEntry->psPtr->numPats' tkBind.c:2827: MatchPatterns: Assertion `psPtr->numPats > patIndex' tkBind.c:2824: MatchPatterns: Assertion `TEST_PSENTRY(psPtr)' From what I can tell at a glance, major changes were made to tkBind.c between 8.6.9 and 8.6.10. I have attached a small script that can be used to reproduce the crashes (see below). Could you guys please take another look at this? Kind regards, Robert #!/bin/sh #\ exec wish "$0" ${1+"$@"} # If you draw a line, the program crashes with Tk since 8.6.10. # # Tested under # Ubuntu 18.04/Tk 8.6.8 (works) # Ubuntu 20.04/Tk 8.6.10 (crashes) # Ubuntu 22.04/Tk 8.6.12 (crashes) # openSUSE 15.4/Tk 8.6.12 (crashes) # among others # # (8.6.9 works, 8.6.11 crashes) # # If Tk was compiled without debugging information, it may take several # attempts to crash the program. proc startLin {c} { unbindCan $c; # try without this (shouldn't crash then) # Some array (move mouse after <ButtonRelease-1>): set arr($c,foofoofoo) "" set arr($c,barbarbar) 1 # or try this instead (and move mouse, leave canvas or draw another line after <ButtonRelease-1>): # set arr($c,foo) "" # set arr($c,bar) 1 # Try this (shouldn't crash then) # unset arr bindCan $c [array get arr] } proc bindCan {c args} { bind $c <ButtonPress-1> "createLin %W %x %y" bind $c <B1-Motion> "drawLin %W %x %y" # Try without the next two lines (shouldn't crash then) bind $c <B1-Motion><Leave> "leaveCan %W" bind $c <B1-Motion><Enter> "enterCan %W" bind $c <ButtonRelease-1> "startLin %W" } proc unbindCan {c} { bind $c <ButtonPress-1> {} bind $c <B1-Motion> {} # Try without the next two lines (shouldn't crash then) bind $c <B1-Motion><Leave> {} bind $c <B1-Motion><Enter> {} bind $c <ButtonRelease-1> {} } proc createLin {c x y} { set x0 [$c canvasx $x] set y0 [$c canvasy $y] $c delete linTag $c create line $x0 $y0 $x0 $y0 -tags linTag } proc drawLin {c x y} { lassign [$c coords linTag] x0 y0 $c coords linTag [list $x0 $y0 [$c canvasx $x] [$c canvasy $y]] } proc leaveCan {c} { # nothing } proc enterCan {c} { # nothing } set c [canvas .c] pack $c startLin $c | |||
User Comments: |
fvogel added on 2022-10-26 19:42:16:
Thanks ;-) Now merged in core-8-6-branch and trunk. Closing. marc_culler (claiming to be Marc Culler) added on 2022-10-25 13:06:14: Well done, François! fvogel added on 2022-10-24 22:19:30: I have a fix, see [aac99dcf401]. All bind tests still pass in the test suite, and the new bind-37.1 stops crashing and is passing now. fvogel added on 2022-10-24 21:29:21: I have committed a testcase demonstrating the crash (or assertion failed in debug mode), see branch bug-43573999ca. I'm now having an understanding of what's happening. Basically, the successive <B1-Motion><Enter> pattern sequences get all promoted because they are partially matching the <B1-Motion> event. When the binding gets deleted in proc A only one instance of the promoted <B1-Motion><Enter> pattern sequences gets deleted in RemovePatSeqFromPromotionLists(), not all promoted (identical) patterne sequences. The next <Motion> event crashes in MatchPattern because of stale pattern sequences still in the promotion array. Stay tuned, I'm working on the fix. fvogel added on 2022-10-23 08:34:56: Oh, I realize I didn't give the recipe to reproduce the crash with either of my two trimmed down examples below: you have to run the code in tclsh, then, in the "." window, click with left button, move the mouse a bit while button-1 is still down, and release the button. At this point it has not yet crashed. Now move the mouse: the next <Motion> event crashes Tk (assertion failed). fvogel added on 2022-10-22 15:30:17: Another trimmed down version, not making use of 'after idle' this time: package require Tk proc A {} { bind .c <B1-Motion><Enter> {} set myv(a) 1 set b [array get myv] # unset b ; # doesn't crash if present bind .c <B1-Motion><Enter> "puts Trigger" } pack [canvas .c] bind .c <ButtonRelease-1> "A" A It is a very strange bug. In proc A above, even if array 'myv' is not used this code is needed to make assertions fail in the bindings code (on Windows and Linux at least - my first experiments on macOS tend to show it's not the case on the mac with -fsanitize=address). Add "unset b" and the failed asserts in the binding code stop. This is very puzzling. To the OP: a simple workaround for your application is to bind to a script that does nothing in proc unbindCan, e.g. bind to {#} instead of bind to {} (which internally deletes the binding). This stops the crash from happening since the binding is no longer deleted but replaced by a void script. fvogel added on 2022-09-27 20:07:08: Very interesting. Here is a trimmed down script triggering the bug: package require Tk proc A {} { bind .c <B1-Motion><Enter> {} after idle [list bind .c <B1-Motion><Enter> "puts Trigger"] } pack [canvas .c] bind .c <ButtonRelease-1> "A" A |
Attachments:
- Address sanitizer output.txt [download] added by fvogel on 2022-09-27 20:20:58. [details]