summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorculler <culler>2023-11-07 14:36:06 (GMT)
committerculler <culler>2023-11-07 14:36:06 (GMT)
commit7515e96928296bec43aecdfb13b8110ab439329b (patch)
treeb1fd3aa88c040b5d4af59b9cbc7c98f47648a4f9 /macosx
parentad6813778940b479f614e40aaa76dc4140648633 (diff)
parentc204c52d17a81ae11cc9722cdc8f403a3794afb1 (diff)
downloadtk-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.c13
-rw-r--r--macosx/tkMacOSXTest.c81
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 *),