Tk Source Code

View Ticket
Login
Ticket UUID: c84f660833546b1b84e7fd3aef930c2f17207461
Title: Tk crashes when toplevel placed on second display, Mac
Type: Bug Version: 8.5.9
Submitter: anonymous Created on: 2014-10-09 01:31:11
Subsystem: 66. Aqua Window Operations Assigned To: kevin_walzer
Priority: 5 Medium Severity: Severe
Status: Closed Last Modified: 2017-09-25 20:32:21
Resolution: Fixed Closed By: fvogel
    Closed on: 2017-09-25 20:32:21
Description:
Placing a Tk top-level window on the second display of a dual display Mac OS system causes a crash when that second display is positioned above the primary display in Mac system display preferences.

Here is how to produce this crash, tested on Mac OS 10.9.5, with two displays with the primary display positioned below the secondary display (using Mac system display preferences). The following wish command attempts to put the toplevel on the second display.

$ wish
% toplevel .t ; wm geometry .t 100x100+500+-500

It crashes will the following output

2014-10-08 17:51:32.982 Wish[92437:507] Error (1000) creating window shape
2014-10-08 17:51:32.983 Wish[92437:507] (
	0   CoreFoundation                      0x00007fff8ad2525c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff8a50ae75 objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff8ad2510c +[NSException raise:format:] + 204
	3   AppKit                              0x00007fff890159b9 _NSCreateWindowWithOpaqueShape2 + 159
	4   AppKit                              0x00007fff89014a21 -[NSWindow _commonAwake] + 3720
	5   AppKit                              0x00007fff890136f7 -[NSWindow _makeKeyRegardlessOfVisibility] + 85
	6   AppKit                              0x00007fff89013670 -[NSWindow makeKeyAndOrderFront:] + 29
	7   Tk                                  0x00000001016c8beb XMapWindow + 134
	8   Tk                                  0x000000010163cafd Tk_MapWindow + 69
	9   Tk                                  0x0000000101644e6a TkInstallFrameMenu + 271
	10  Tcl                                 0x00000001017c770d TclServiceIdle + 87
	11  Tcl                                 0x00000001017aecee Tcl_DoOneEvent + 344
	12  Tk                                  0x0000000101624a41 Tk_MainLoop + 33
	13  Tk                                  0x000000010163003f Tk_MainEx + 1445
	14  Wish                                0x000000010160553f Wish + 9535
	15  libdyld.dylib                       0x00007fff8a7305fd start + 1
	16  ???                                 0x0000000000000001 0x0 + 1
)
2014-10-08 17:51:32.993 Wish[92437:507] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error (1000) creating window shape'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff8ad2525c __exceptionPreprocess + 172
	1   libobjc.A.dylib                     0x00007fff8a50ae75 objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff8ad2510c +[NSException raise:format:] + 204
	3   AppKit                              0x00007fff890159b9 _NSCreateWindowWithOpaqueShape2 + 159
	4   AppKit                              0x00007fff89014a21 -[NSWindow _commonAwake] + 3720
	5   AppKit                              0x00007fff890136f7 -[NSWindow _makeKeyRegardlessOfVisibility] + 85
	6   AppKit                              0x00007fff89013670 -[NSWindow makeKeyAndOrderFront:] + 29
	7   Tk                                  0x00000001016c8beb XMapWindow + 134
	8   Tk                                  0x000000010163cafd Tk_MapWindow + 69
	9   Tk                                  0x0000000101644e6a TkInstallFrameMenu + 271
	10  Tcl                                 0x00000001017c770d TclServiceIdle + 87
	11  Tcl                                 0x00000001017aecee Tcl_DoOneEvent + 344
	12  Tk                                  0x0000000101624a41 Tk_MainLoop + 33
	13  Tk                                  0x000000010163003f Tk_MainEx + 1445
	14  Wish                                0x000000010160553f Wish + 9535
	15  libdyld.dylib                       0x00007fff8a7305fd start + 1
	16  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
/usr/bin/wish: line 2: 92437 Abort trap: 6           "$(dirname $0)/../../System/Library/Frameworks/Tk.framework/Versions/8.5/Resources/Wish.app/Contents/MacOS/Wish" "$@"

This may appear to be a very obscure bug actually it is quite common, the crashes being reported over 50 times for the molecular visualization Tk app I develop, UCSF Chimera.

  https://plato.cgl.ucsf.edu/trac/chimera/ticket/11677

Also it has been reported as a Python bug when the Tk IDLE shell is used and a tooltip appears

   http://bugs.python.org/issue16177

Here is why it happens frequently.  For users with dual display Mac systems the second display by default is logically placed to the right of the primary display.  If that display has more vertical pixels then the primary display then the top of that secondary display is above the top of the primary display.  This situation is the norm since the primary display is often a laptop, and the secondary often a large external display with more pixels.  When a toplevel is placed on that secondary display above the position of the top of the primary display then the crash occurs.  In both the Chimera and IDLE crash reports this happens for tooltips shown in popup balloons.  This makes it an especially aggravating bug for the user -- they accidentally hover the mouse over a Tk window triggering a tooltip balloon window which causes a crash before that tooltip is shown.  The user has no idea why the app crashed -- they weren't doing anything.

It took a long time for me to figure this out.

You may think the cause is related to the negative y position specified in the geometry "wm geometry .t 100x100+500+-500".  But remarkably if the second display is to the left of the primary and a negative x position is used "wm geometry .t 100x100+-500+500" everything works correctly without a crash.  So the bug is specific to the y axis!

A search for the routine seen in the crash trace "makeKeyAndOrderFront" in the tk code finds it in one place tkMacOSXSubwindows.c in XMapWindow().  I placed a print statement in TkMacOSXMakeRealWindowExist() in tkMacOSXWm.c to print the requested window geometry at the line
"    [window setFrame:geometry display:NO];" and the y window position appeared to be correct.  In the Mac native NSWindow api the y coordinates increase from bottom to top of screen, while Tk y coordinates increase from 0 at top of primary screen to bottom.  So Tk has translated the negative y position, such as +500+-500 to 500,1780.  So I did not discern any clue as to the cause of the crash with this debugging.

A possibly revealing observation is that if the toplevel is displayed on the primary display and then an attempt is made to move it with "wm geometry" to the secondary display, then no crash happens, and the window will not move to the secondary display, and instead is moved to the very bottom of the primary display.  It is only when the toplevel is mapped first on the secondary display that the crash happens.

Unfortunately (or actually fortunately) I don't know enough about the native Mac window toolkit or the Tk Mac code to understand what is causing this problem.  The reported Apple exception

'NSInternalInconsistencyException', reason: 'Error (1000) creating window shape'

should mean something to a Mac developer.

Good luck!  I would love to see a solution to this.  For now I simply will disable tooltips that have negative y positions.
User Comments: fvogel added on 2017-09-25 20:32:21:

This was also reported elsewhere, see [3608963].


marc_culler (claiming to be Marc Culler) added on 2016-07-19 19:06:55:
Yikes!  You are right, Tom, I dropped the Height term somehow.  Thank you for noticing that!  I'll post a new patch, to be applied on top of the one that was already committed.

tom_goddard (claiming to be Tom Goddard) added on 2016-07-19 18:11:41:
Thanks for the patch Marc.  I have confirmed that it fixes the dual display case that I have in UCSF Chimera.

Your patch has an error in the y placement.  Your patch used

      tkMacOSXZeroScreenHeight - Y - YOff

but

      tkMacOSXZeroScreenHeight - Y - YOff - Height

is needed to match the original code and correctly position the windows in y.

kevin_walzer added on 2016-07-17 03:20:38:
Thanks for the patch, Marc. Crash no longer present in sample code. Committing and closing.

anonymous (claiming to be Marc Culler) added on 2016-07-16 22:17:38:
Well, I guess you guys will all be happy to stop hearing from your annoyed users about this crash.

The problem turned out to be one of those classic C bugs.  There is a spot in XMoveResizeWindow where a bounding rectangle was computed, and the arithmetic expression involved a mixture of signed integers, unsigned integers and doubles.  When y was less than -height, the C conversion rules caused this computation to differ from the intended value by 2.0^32, triggering the exception which then caused the crash.

The problem was also ancient.  I got the same crash with the Tk 8.5.9 which Apple ships with OSX 10.9. (Or, should I say MacOS 10.9.)

I will upload a patch so you guys can test it on your systems, and also send the patch to Kevin.

I tested on a Mavericks laptop with a second monitor.  When I tried entering

% toplevel .t ; wm geometry .t 100x100+500+-500

a tiny little window popped up in the middle of my big monitor.

tom_goddard (claiming to be Tom Goddard) added on 2016-07-16 18:34:52:
Great work Marc determining this bug can be reproduced with a single display.

I am the one who submitted this bug.  Although it does not require two displays I guess that the crash is common on dual display systems and rare on single display systems.  I get voluntarily submitted reports of this crash every few weeks for the last couple years (about 100 reports so far) for the molecular visualization program UCSF Chimera and every one is on a dual display system, almost always a laptop with a larger external monitor.  The external monitor is the non-primary display almost always configured side-by-side with the primary display in Mac preferences, but since it has more vertical pixels it extends above the primary display.  Since the secondary display x,y coordinates use origin 0,0 from the primary display, the secondary display top region has negative y coordinates.  So tool tips and menus that popup near the top the secondary display cause a crash.  With just a single display it would be rare for a window to be created with position having negative y coordinate, but it is all too common with two displays.

jal_frezie added on 2016-07-16 13:13:09:
Regarding the previous poster's assertion that this is really a timing problem, while it is true that Tk only actually crashes if the wm geometry command is executed immediately after creating the toplevel window, it never succeeds in positioning the window correctly if there is a second screen with negative y coordinates. It always moves somewhere with positive y coordinates.

anonymous (claiming to be Marc Culler) added on 2016-07-16 13:00:18:
While this is a serious bug, the information in the report is quite misleading. A bit more testing reveals the following:

1. This has nothing to do with multiple displays.  The command:
toplevel .t ; wm geometry .t 100x100+500+-500
crashes on single-display systems.

2. The crash does not occur with the slightly different command:
toplevel .t ; wm geometry .t 100x100+500+-100
In fact, it does not crash unless the y coordinate is less than -height. (This probably explains why the crash is not occurring with popup menus.)

3. The crash does not occur if the geometry command is issued on a separate line, indicating that this is really a timing problem.

4. The actual exception (visible in the Tk crash report) is an assertion error caused by a Window frame whose coordinates are less than the smallest integer or greater than the largest integer.

So, the way it looks to me is that the geometry command is being executed before the NSWindow data structures have been fully initialized. In particular, floating point arithmetic operations are being performed with unitialized values in a frame rectangle, and when origin.y < -size.height this leads to values in the struct NSRect which lie outside the interval of valid integer values. Presumably this is possible because some or all of the initialization takes place asynchronously, in the App Kit event loop.  I would guess that a solution might involve forcing Tk to wait in XMapWindow until the NSWindow data structures are in a stable state.

jal_frezie added on 2016-06-14 12:38:28:
I don't think you need a two-monitor setup to replicate it -- I've also seen comments about it from people who deliberately place a window off-screen in order to set up some content before making it visible.

I have found that if you post a menu to a screen area with a negative Y coordinate, e.g., using tk_popup, it appears in the right place. So possibly the problem has been solved in another part of the code.

dkf added on 2014-10-13 13:23:10:

Also crashes with 8.6.1.

2014-10-13 14:20:35.246 Wish[7174:707] An uncaught exception was raised
2014-10-13 14:20:35.247 Wish[7174:707] Error (1000) creating window shape
2014-10-13 14:20:35.275 Wish[7174:707] (
	0   CoreFoundation                      0x00007fff8bf6ab06 __exceptionPreprocess + 198
	1   libobjc.A.dylib                     0x00007fff884053f0 objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff8bf6a8dc +[NSException raise:format:] + 204
	3   AppKit                              0x00007fff8eeeb9ff _NSCreateWindowWithOpaqueShape2 + 325
	4   AppKit                              0x00007fff8eeea340 -[NSWindow _commonAwake] + 2002
	5   AppKit                              0x00007fff8ef9a75b -[NSWindow _makeKeyRegardlessOfVisibility] + 88
	6   AppKit                              0x00007fff8ef9a6c5 -[NSWindow makeKeyAndOrderFront:] + 25
	7   Tk                                  0x00000001000d42c1 XMapWindow + 156
	8   Tk                                  0x0000000100038f9e Tk_MapWindow + 89
	9   Tk                                  0x0000000100042209 MapFrame + 62
	10  Tcl                                 0x0000000100254476 TclServiceIdle + 76
	11  Tcl                                 0x00000001002375d4 Tcl_DoOneEvent + 329
	12  Tk                                  0x000000010001d5a4 Tk_MainLoop + 24
	13  Tk                                  0x000000010002b858 Tk_MainEx + 1596
	14  Wish                                0x000000010000549f main + 56
	15  Wish                                0x00000001000053c0 start + 52
)
2014-10-13 14:20:35.276 Wish[7174:707] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error (1000) creating window shape'
*** First throw call stack:
(
	0   CoreFoundation                      0x00007fff8bf6ab06 __exceptionPreprocess + 198
	1   libobjc.A.dylib                     0x00007fff884053f0 objc_exception_throw + 43
	2   CoreFoundation                      0x00007fff8bf6a8dc +[NSException raise:format:] + 204
	3   AppKit                              0x00007fff8eeeb9ff _NSCreateWindowWithOpaqueShape2 + 325
	4   AppKit                              0x00007fff8eeea340 -[NSWindow _commonAwake] + 2002
	5   AppKit                              0x00007fff8ef9a75b -[NSWindow _makeKeyRegardlessOfVisibility] + 88
	6   AppKit                              0x00007fff8ef9a6c5 -[NSWindow makeKeyAndOrderFront:] + 25
	7   Tk                                  0x00000001000d42c1 XMapWindow + 156
	8   Tk                                  0x0000000100038f9e Tk_MapWindow + 89
	9   Tk                                  0x0000000100042209 MapFrame + 62
	10  Tcl                                 0x0000000100254476 TclServiceIdle + 76
	11  Tcl                                 0x00000001002375d4 Tcl_DoOneEvent + 329
	12  Tk                                  0x000000010001d5a4 Tk_MainLoop + 24
	13  Tk                                  0x000000010002b858 Tk_MainEx + 1596
	14  Wish                                0x000000010000549f main + 56
	15  Wish                                0x00000001000053c0 start + 52
)
libc++abi.dylib: terminate called throwing an exception
/usr/local/bin/wish8.6: line 2:  7174 Abort trap: 6           "$(dirname $0)/../../../Library/Frameworks/Tk.framework/Versions/8.6/Resources/Wish.app/Contents/MacOS/Wish" "$@"


kevin_walzer added on 2014-10-13 01:45:54:
I lack a two-monitor setup to investigate this, but will leave open if that changes.

Attachments: