| Ticket UUID: | d8f9640fcd97c952444ff4e1aa9f4066982b9d62 | |||
| Title: | Segfault under Windows when executing test file menu.test with "-singleproc 0" | |||
| Type: | Bug | Version: | trunk | |
| Submitter: | erikleunissen | Created on: | 2025-08-11 15:53:02 | |
| Subsystem: | 10. Generic Menus | Assigned To: | jan.nijtmans | |
| Priority: | 5 Medium | Severity: | Severe | |
| Status: | Closed | Last Modified: | 2026-09-25 08:31:15 | |
| Resolution: | Fixed | Closed By: | nobody | |
| Closed on: | ||||
| Description: |
A segfault occurs when executing the test file menu.test with -singleproc 0.
Currently, all.tcl does not support using "-singleproc 0". Therefore, you need
to change in all.tcl:
tcltest::configure -singleproc 1
to
tcltest::configure -singleproc 0
The OS kills the process in which menu.test is executing. Any remaining test
files keep on executing each in their separate process without problem.
Therefore, this issue is specific for the test file menu.test. The invocation
below selects that test file for the sake of efficiency.
- Tk version: Tk9.1a0 (but the same happens with Tk9.0.2 and Tk8.6.16)
- Invocation 1: wish91.exe all.tcl -file menu.test
- Invocation 2: tktest.exe all.tcl -file menu.test
- You may add "-match NONE" to the above invocations: executing the test file
suffices, executing any tests is not necessary.
- Reproducibility: always
- Back trace for tktest.exe from Dr. Mingw:
tktest.exe caused an Access Violation at location 000000006B067367 in module tcl9tk91.dll Reading from location 0000000000000068.
AddrPC Params
000000006B067367 000000000065FAF0 0000000003746720 0000000003746838 tcl9tk91.dll!ConfigureMenu.isra.0+0x287
000000006B069D99 00000000006E4400 0000000003699240 0000000000000000 tcl9tk91.dll!Tk_MenuObjCmd+0x289
000000006E7DBF68 000000000065FAF0 000000006E87CD90 0000000003031090 tcl91.dll!TclNRRunCallbacks+0x68
000000006E7DDE11 000000000065FAF0 00000000036CEF00 000000000001F2FA tcl91.dll!TclEvalEx+0x581
000000006E891E03 000000006B142C90 0000000000000028 00000000006A6D80 tcl91.dll!Tcl_FSEvalFileEx+0x1a3
000000006B06568B 0000000000000006 0000000000000005 0000000000401590 tcl9tk91.dll!Tk_MainExW+0x2bb
0000000000401748 000000000000007C 0000000000000005 0000000000408978 tktest.exe!wmain+0x48
00000000004013EE 0000000000000000 0000000000000000 0000000000000000 tktest.exe!__tmainCRTStartup+0x26e [/home/abuild/rpmbuild/BUILD/mingw-w64-v7.0.0/mingw-w64-crt/crt/crtexe.c @ 334]
000000000040150B 0000000000000000 0000000000000000 0000000000000000 tktest.exe!WinMainCRTStartup+0x1b [/home/abuild/rpmbuild/BUILD/mingw-w64-v7.0.0/mingw-w64-crt/crt/crtexe.c @ 195]
0000000077B059CD 0000000000000000 0000000000000000 0000000000000000 kernel32.dll!BaseThreadInitThunk+0xd
0000000077C6385D 0000000000000000 0000000000000000 0000000000000000 ntdll.dll!RtlUserThreadStart+0x1d
| |||
| User Comments: |
serhiy.storchaka added on 2026-09-25 08:31:15:
Fixed in 8.6.18 and 9.0.4 by [ff1d83ab98] (merged as [5046dd9646] and [0f90da4514]): the menu code checks for a missing parent before comparing its class. Closing. jan.nijtmans added on 2026-03-10 16:27:36: Ashok's proposal now [f3e40c73322e1751|merged]. I could reproduce the crash. No crash is better - at least - than a crash. Still - test-cases are failing with -singleproc 0: menu.test So, keeping this ticket open. emiliano added on 2026-01-16 21:05:27: A bit of context: The bug originates trying to fix this bug. This work leads to TIP 359 afterwards, making Tk usable in such environment. WRT to what the code is trying to do, in words of dkf:
I will add that _NET_WM_WINDOW_TYPE_DROPDOWN_MENU should also apply to menubutton's associated menu. The real fix for this bug implies a robust way to figure this out (easier said than done). oehhar added on 2026-01-13 10:03:23: I would be in favor to remove the "-tearoff" option in 9.1. I think, this would make the code much easier. Harald apnadkarni added on 2026-01-13 08:18:28: Oops, I meant Christian's patch apnadkarni added on 2026-01-13 08:15:34: I am clearly over my head in Tk! No surprise. I'll leave it to folks who are actually competent to address this, whether via my branch or Emiliano's patch. That's assuming it is fixable in the first place, which based on comments from Emiliano and Christian, I'm unsure of. chw added on 2026-01-12 19:26:16: At least can we agree now, that this is an almost grown-up bug present since late point releases of 8.5, bummer! emiliano added on 2026-01-12 19:05:59: chw: yes, you are right, is the pointer which is there, not the struct itself! So the code is plain wrong. I have to admit that menu code is non trivial, given the mix of menubars, tearoffs, popup and clones which are all named "menu". Worse than that, you can convert them to plain widgets. menu .menu -type tearoff .menu add command -label hello wm forget .menu place .menu -x 50 -y 50 Madness! chw added on 2026-01-12 18:16:27: @emiliano, unfortunately a Tk_Window is an opaque handle with pointer size.
And its real beef is managed elsewhere, i.e. not in the tkMenu.c module.
I believe the intention for the if-clause was something along
int typeFlag = TK_MAKE_MENU_POPUP;
...
while (1) {
Tk_Window parent = Tk_Parent(tkwin);
if (Tk_IsTopLevel(parent)) {
typeFlag = TK_MAKE_MENU_DROPDOWN;
break;
}
if (Tk_Class(parent) != Tk_Class(menuPtr->tkwin)) {
break;
}
tkwin = parent;
}
The typeFlag goes down to the X11 platform specific menu creation
code which uses it to set some obscure window manager hints (which
may or may not have further consequences on the user experience).
Other windowing systems are not affected by the difference between
TK_MAKE_MENU_POPUP and TK_MAKE_MENU_DROPDOWN.
emiliano added on 2026-01-12 17:53:15: @chw: In the case of the menu widget, the first member of the widget record is a Tk_Window. In generic/tkMenu.h, the definition is
typedef struct TkMenu {
Tk_Window tkwin;
/* all other members */
} TkMenu;
in which case
((TkMenu *) tkwin)
points to the widget record. Incidentally. Until someone change the order.
chw added on 2026-01-12 16:25:36: emiliano, it is worse, since tkwin being a Tk_Window never can be casted to a TkMenu. emiliano added on 2026-01-12 14:59:15: A slightly semantically better fix for this issue is attached, checking in the loop if the parent is a toplevel widget. This will fix the crash but NOT fix all other issues that might arise from widgets having the "wrong" class.
There's also a further potential bug from this code. The class can be set on any frame, toplevel or ttk widget, and the line after the loop
if (((TkMenu *) tkwin)->menuType == MENUBAR) {
assume that tkwin is a TkMenu*, but this is not necessarily so. Consider when applied to this code
frame .m -class Menu
menu .m.m
In this case, tkwin will point to .m, which is not a menu despite being of Menu class. I think a more robust solution is needed.
oehhar added on 2026-01-12 14:09:49: Oh, no! The old issue, that the main window class is named following the file name. Couldn't we stop this? That is why it crashes, if the test file is named "menu.test"... I had that once with a file "scale.tcl", which gave the class "scale", and the main Menu got everything from the scale widget... Thanks for all, Harald emiliano added on 2026-01-12 13:54:37: Reading apn's commit and further errors in tests, I realized that the problem is that the main window (aka ".") is of class Menu, leading to all kinds of problems.
This explain why the loop here
https://core.tcl-lang.org/tk/artifact?name=3d58a19246bdb50e&ln=1636-1643
crashes, as it walks the window hierarchy up until the main window, and then Tk_Parent(tkwin) returns NULL.
Also explains why, after apn's modification, test fails with errors like
```
unknown option "-type"
while executing
". cget -type"
invoked from within ...
```
as the main window is now of the "wrong" class.
The shortest script to fire this bug (present on both Tk 8 and 9) is (spanish locale):
$ cat crash.tcl
package require Tk
puts [winfo class .]; flush stdout
menu .m
$ wish crash.tcl -name Menu
Menu
Violación de segmento (`core' generado)
Note that this will also happen if the main script is called simply "menu"
$ mv crash.tcl menu
$ wish menu
Menu
Violación de segmento (`core' generado)
erikleunissen added on 2026-01-12 13:15:20: Regarding:
> I committed a possible workaround for that now.
Thanks!
I just updated and recompiled. The previous compile error is gone.
The compile now stops at another position with:
/home/erik/priv/Develop/tk-fossil/win/tkWinSysTray.c: In function 'WinSysNotifyCmd':
/home/erik/priv/Develop/tk-fossil/win/tkWinSysTray.c:1134:2: warning: implicit declaration of function 'SetCurrentProcessExplicitAppUserModelID' [-Wimplicit-function-declaration]
1134 | SetCurrentProcessExplicitAppUserModelID(appid);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/erik/priv/Develop/tk-fossil/win/tkWinSysTray.c:1166:19: error: 'NOTIFYICON_VERSION_4' undeclared (first use in this function); did you mean 'NOTIFYICON_VERSION'?
1166 | ni.uVersion = NOTIFYICON_VERSION_4;
| ^~~~~~~~~~~~~~~~~~~~
| NOTIFYICON_VERSION
/home/erik/priv/Develop/tk-fossil/win/tkWinSysTray.c:1166:19: note: each undeclared identifier is reported only once for each function it appears in
make: *** [Makefile:825: tkWinSysTray.o] Error 1
jan.nijtmans added on 2026-01-12 12:49:52: > I still get the same compile error after having merged the latest trunk (commit c269205209) into the bug-fix branch. I committed a possible workaround for that now. erikleunissen added on 2026-01-12 12:29:37: Regarding: > Feels like this indicates that there is some interdependency between files in some fashion. That is possible (but still an issue/bug) in mode "-singleproc 1". However, it's impossible in mode "-singleproc 0", since each test file is evaluated in a separate process (and therefore a separate interpreter). So, probably obvious, but nevertheless to prevent misunderstanding: could you confirm that this was observed with "-singleproc 1" ? apnadkarni added on 2026-01-12 12:02:54: The other curious thing I noticed is that when I run menu.test by itself (using the -file option), I just see the test failures noted previously logged to the terminal. However, if I run the entire suite, I get a large number of error popups while menu.test is running similar to those below:
or
or while running radiobutton.test,
Feels like this indicates that there is some interdependency between files in some fashion. Otherwise, why the difference in behaviour where a full run shows popups but just running menu.test does not? erikleunissen added on 2026-01-12 11:54:50: I still get the same compile error after having merged the latest trunk (commit c269205209) into the bug-fix branch. (B.t.w. I'm using the mingw-w64 cross-toolchain from Linux, which normally builds fine). apnadkarni added on 2026-01-12 11:47:53: @oehhar, I already tried creating a test case but could not ascertain exactly what conditions result in the parent being NULL other than running the test suite in @erikleunissen, the failures cannot be seen on main trunk since menu.test simply crashes with
oehhar added on 2026-01-12 11:46:08: Isn't this fixed by Jan by this commit: [b9b5d4fa0ec9f9f4] today in the main branch? Just an idea, Harald kevin_walzer added on 2026-01-12 11:41:47: Jan just committed a fix for the compiler error to trunk. Try updating and rebuilding. erikleunissen added on 2026-01-12 11:21:24: I can't test that because I get this compile error for MS Windows:
/home/erik/priv/Develop/tk-fossil/win/tkWinIco.c: In function 'GetFileIcon':
/home/erik/priv/Develop/tk-fossil/win/tkWinIco.c:283:17: error: 'SHIL_JUMBO' undeclared (first use in this function)
283 | else shil = SHIL_JUMBO;
| ^~~~~~~~~~
/home/erik/priv/Develop/tk-fossil/win/tkWinIco.c:283:17: note: each undeclared identifier is reported only once for each function it appears in
make: *** [Makefile:825: tkWinIco.o] Error 1
oehhar added on 2026-01-12 11:17:36: Thanks, great! Eric, you were the initial submitter, right? Is the patch effective for you? Thanks! Harald erikleunissen added on 2026-01-12 11:10:59: * Regarding the option -singleproc in general: Since the inclusion of RFE "Simplify testfile initialization" (commit #c2d3890e3c), this option can be simply passed on the command line instead of editing the file all.tcl. (At the time of filing this ticket, that RFE wasn't merged yet.) * Regarding: > Note that setting singleProc to 0 will cause other tests in menu.test to fail > as they expect a certain common environment to have been set up. This indicates a bug. However, I cannot reproduce this on Linux, and alas I currently cannot test this on MS Windows. I'm happy to investigate this further, but I'd recommend to file a separate ticket for this issue, with more specific information about the extra test failures. oehhar added on 2026-01-12 09:03:14: Thanks, Ashok, great. It should be possible to create a test case for this. Perhaps, Csaba can comment on the fix... Thanks for all, Harald apnadkarni added on 2026-01-12 08:02:44: Proposed fix in [ff1d83ab]. Tested by setting singleProc to 0 in all.tcl as suggested. Note that setting singleProc to 0 will cause other tests in menu.test to fail as they expect a certain common environment to have been set up. In addition to being a "tactical" fix of checking for a NULL pointer, it also seems to be the logically correct fix. The loop is looking for the furthest ancestor of the same class so breaks if the class is different. If there is no further ancestor (parent == NULL) that also means the current tkwin is the furthest ancestor and should therefore exit the loop. But then again, I do not really know Tk so someone should verify. oehhar added on 2025-08-19 20:15:20: My test branch is in commit [b20bb269], which starts the branch [d8f9640f-mswin-segfault-menu-test]. oehhar added on 2025-08-19 20:08:22: Your stack trace tells, that the menu command is invoked and it crashes in the configure option. This is in the generic code and not Windows specific. As the test file crashes without tests (and before any tests), the issue must be in the test file initialization. We only have in menu.test: testutils import image imageInitoutside any test. # commenting this out does not cure the segfault. In line 153, there is outside of any test: # Used for 2.1 - 2.30 tests destroy .m1 menu .m1 This looks bogus, but commenting it out does not cure the segfault. I tried to comment out any command outside of a test with no change. Sorry, Harald oehhar added on 2025-08-19 19:39:48: I tried to reproduce with options symbols and noembed on the current main branches and MS-VS2022 on 64 bit and I get: nmake -f makefile.vc test OPTS=noembed,symbols TCLDIR=c:\test\fossil\tcl\main TESTFLAGS="-file menu.test -match NONE" ... Microsoft (R) Program Maintenance Utility, Version 14.44.35214.0 ... Test file error: child killed: segmentation violation So, there is a child process started and this one segfaults. It would be great to have the child process stopping for a while, so I may attach the VisualStudio debugger. The stack trace looks similar to this bug: https://core.tcl-lang.org/tk/tktview/f4213443734676892385. Mostly, a script is evaluated by a callback, which removes some resources. When the call returns, the resources are gone. I was looking to it by using the debugger and tracing through the code. But this is now not possible, as there is no possibility to attach the debugger. Sorry, Harald oehhar added on 2025-08-12 06:28:17: Thanks for the catch. I have traced similar issues with the debugger. It is typically a misplaced tcl_preserve. No time at the moment, sorry. Harald | |||
Attachments:
- tkMenu.diff [download] added by emiliano on 2026-01-12 14:59:44. [details]
