diff options
author | culler <culler> | 2023-11-07 14:36:06 (GMT) |
---|---|---|
committer | culler <culler> | 2023-11-07 14:36:06 (GMT) |
commit | 7515e96928296bec43aecdfb13b8110ab439329b (patch) | |
tree | b1fd3aa88c040b5d4af59b9cbc7c98f47648a4f9 /macosx | |
parent | ad6813778940b479f614e40aaa76dc4140648633 (diff) | |
parent | c204c52d17a81ae11cc9722cdc8f403a3794afb1 (diff) | |
download | tk-7515e96928296bec43aecdfb13b8110ab439329b.zip tk-7515e96928296bec43aecdfb13b8110ab439329b.tar.gz tk-7515e96928296bec43aecdfb13b8110ab439329b.tar.bz2 |
Fix [09a11fb1228f]: Aqua use-after-free can occur when a posted menu is destroyed. Thanks to Christopher Chavez.
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/tkMacOSXMenu.c | 13 | ||||
-rw-r--r-- | macosx/tkMacOSXTest.c | 81 |
2 files changed, 89 insertions, 5 deletions
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 7a69876..b510422 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -888,14 +888,17 @@ TkpDestroyMenuEntry( TKMenu *menu; NSInteger index; - if (mePtr->platformEntryData && mePtr->menuPtr->platformData) { - menu = (TKMenu *) mePtr->menuPtr->platformData; + if (mePtr->platformEntryData) { menuItem = (NSMenuItem *) mePtr->platformEntryData; - index = [menu indexOfItem:menuItem]; + if (mePtr->menuPtr->platformData) { + menu = (TKMenu *) mePtr->menuPtr->platformData; + index = [menu indexOfItem:menuItem]; - if (index > -1) { - [menu removeItemAtIndex:index]; + if (index > -1) { + [menu removeItemAtIndex:index]; + } } + [menuItem setTag:(NSInteger) NULL]; [menuItem release]; mePtr->platformEntryData = NULL; } diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c index 3f178c3..82c207d 100644 --- a/macosx/tkMacOSXTest.c +++ b/macosx/tkMacOSXTest.c @@ -25,6 +25,7 @@ static Tcl_ObjCmdProc DebuggerObjCmd; #endif static Tcl_ObjCmdProc PressButtonObjCmd; +static Tcl_ObjCmdProc MoveMouseObjCmd; static Tcl_ObjCmdProc InjectKeyEventObjCmd; static Tcl_ObjCmdProc MenuBarHeightObjCmd; @@ -58,6 +59,7 @@ TkplatformtestInit( Tcl_CreateObjCommand(interp, "debugger", DebuggerObjCmd, NULL, NULL); #endif Tcl_CreateObjCommand(interp, "pressbutton", PressButtonObjCmd, NULL, NULL); + Tcl_CreateObjCommand(interp, "movemouse", MoveMouseObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "injectkeyevent", InjectKeyEventObjCmd, NULL, NULL); Tcl_CreateObjCommand(interp, "menubarheight", MenuBarHeightObjCmd, NULL, NULL); return TCL_OK; @@ -266,6 +268,85 @@ PressButtonObjCmd( return TCL_OK; } +/* + *---------------------------------------------------------------------- + * + * MoveMouseObjCmd -- + * + * This Tcl command simulates a mouse motion to a specific screen + * location. It injects an NSEvent into the NSApplication event queue, + * as opposed to adding events to the Tcl queue as event generate would + * do. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +MoveMouseObjCmd( + TCL_UNUSED(void *), + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + int x = 0, y = 0, i, value; + CGPoint pt; + NSPoint loc; + NSEvent *motion; + NSArray *screens = [NSScreen screens]; + CGFloat ScreenHeight = 0; + enum {X=1, Y}; + + if (screens && [screens count]) { + ScreenHeight = [[screens objectAtIndex:0] frame].size.height; + } + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "x y"); + return TCL_ERROR; + } + for (i = 1; i < objc; i++) { + if (Tcl_GetIntFromObj(interp,objv[i],&value) != TCL_OK) { + return TCL_ERROR; + } + switch (i) { + case X: + x = value; + break; + case Y: + y = value; + break; + default: + break; + } + } + pt.x = loc.x = x; + pt.y = y; + loc.y = ScreenHeight - y; + + /* + * We set the timestamp to 0 as a signal to tkProcessMouseEvent. + */ + + CGWarpMouseCursorPosition(pt); + motion = [NSEvent mouseEventWithType:NSMouseMoved + location:loc + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + eventNumber:0 + clickCount:1 + pressure:0]; + [NSApp postEvent:motion atStart:NO]; + return TCL_OK; +} + static int InjectKeyEventObjCmd( TCL_UNUSED(void *), |