summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkMenu.c1
-rw-r--r--macosx/tkMacOSXMenu.c13
-rw-r--r--macosx/tkMacOSXTest.c81
-rw-r--r--tests/menu.test34
4 files changed, 124 insertions, 5 deletions
diff --git a/generic/tkMenu.c b/generic/tkMenu.c
index 3a47724..07fc3f1 100644
--- a/generic/tkMenu.c
+++ b/generic/tkMenu.c
@@ -1221,6 +1221,7 @@ DestroyMenuInstance(
DestroyMenuEntry);
menuPtr->numEntries = i;
}
+ menuPtr->active = -1;
if (menuPtr->entries != NULL) {
ckfree(menuPtr->entries);
menuPtr->entries = NULL;
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c
index 5f1d9fd..45ae1e6 100644
--- a/macosx/tkMacOSXMenu.c
+++ b/macosx/tkMacOSXMenu.c
@@ -893,14 +893,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 7a28e01..cd5479f 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 *),
diff --git a/tests/menu.test b/tests/menu.test
index 078604a..d207269 100644
--- a/tests/menu.test
+++ b/tests/menu.test
@@ -14,6 +14,8 @@ imageInit
# find the earth.gif file for use in these tests (tests 2.*)
set earthPhotoFile [file join [file dirname [info script]] earth.gif]
testConstraint hasEarthPhoto [file exists $earthPhotoFile]
+testConstraint pressbutton [llength [info commands pressbutton]]
+testConstraint movemouse [llength [info commands movemouse]]
test menu-1.1 {Tk_MenuCmd procedure} -body {
menu
@@ -4278,6 +4280,38 @@ test menu-40.14 {identifiers - reserved word} -setup {
destroy .m
} -result {2}
+test menu-40.1 {Use-after-free if menu destroyed while posted - bug 09a11fb1228f} -setup {
+} -constraints {pressbutton} -body {
+ set done false
+ event generate {} <Motion> -x 100 -y 100
+ toplevel .t
+ menu .t.m
+ .t.m add command -command {puts Marco} -label Marco
+ .t.m add command -command {puts Polo} -label Polo
+ after 1000 {.t.m post 500 500}
+ after 2000 {destroy .t}
+ after 2500 {pressbutton 530 510}
+ after 3000 {set done true}
+ tkwait variable done
+}
+
+test menu-40.2 {Use-after-free if menu destroyed while posted - bug 09a11fb1228f} -setup {
+} -constraints {movemouse} -body {
+ set done false
+ event generate {} <Motion> -x 100 -y 100
+ toplevel .t
+ menu .t.m
+ .t.m add command -command {puts Marco} -label Marco
+ .t.m add command -command {puts Polo} -label Polo
+ after 1000 {.t.m post 500 500}
+ after 2000 {movemouse 530 510}
+ after 3000 {destroy .t}
+ after 3500 {movemouse 530 530}
+ after 4000 pressbutton 530 530
+ after 4500 {set done true}
+ tkwait variable done
+ pressbutton 530 510
+}
# cleanup
imageFinish