From 49e17cbfd71f35281045dd68a87086fd280be310 Mon Sep 17 00:00:00 2001 From: Kevin Wojniak Date: Mon, 23 May 2016 21:41:52 -0700 Subject: [PATCH] Fix "attempt to destroy map with items inside" when menuManager is deallocated Fixes #58. The map needs to have its contents properly freed which requires releasing the properly retaining the NSMenuItem object. --- darwin/main.m | 1 - darwin/map.m | 16 ++++++++++++++++ darwin/menu.m | 20 +++++++++++++++----- darwin/uipriv_darwin.h | 2 ++ 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/darwin/main.m b/darwin/main.m index 15c91fea..e8985e99 100644 --- a/darwin/main.m +++ b/darwin/main.m @@ -129,7 +129,6 @@ void uiUninit(void) { @autoreleasepool { - uninitMenus(); [appDelegate() release]; [realNSApp() setDelegate:nil]; [realNSApp() release]; diff --git a/darwin/map.m b/darwin/map.m index 67b5edb6..46a7b8d2 100644 --- a/darwin/map.m +++ b/darwin/map.m @@ -41,3 +41,19 @@ void mapDelete(struct mapTable *m, void *key) { NSMapRemove(m->m, key); } + +void mapWalk(struct mapTable *m, void (*f)(void *key, void *value)) +{ + NSMapEnumerator e = NSEnumerateMapTable(m->m); + void *k = NULL; + void *v = NULL; + while (NSNextMapEnumeratorPair(&e, &k, &v)) { + f(k, v); + } + NSEndMapTableEnumeration(&e); +} + +void mapReset(struct mapTable *m) +{ + NSResetMapTable(m->m); +} diff --git a/darwin/menu.m b/darwin/menu.m index 12ce5c26..fcf819da 100644 --- a/darwin/menu.m +++ b/darwin/menu.m @@ -27,6 +27,14 @@ enum { typeSeparator, }; +static void mapItemReleaser(void *key, void *value) +{ + uiMenuItem *item; + + item = (uiMenuItem *)value; + [item->item release]; +} + @implementation menuManager - (id)init @@ -43,6 +51,9 @@ enum { - (void)dealloc { + uninitMenus(); + mapWalk(self->items, mapItemReleaser); + mapReset(self->items); mapDestroy(self->items); [super dealloc]; } @@ -234,16 +245,16 @@ static uiMenuItem *newItem(uiMenu *m, int type, const char *name) item->type = type; switch (item->type) { case typeQuit: - item->item = appDelegate().menuManager.quitItem; + item->item = [appDelegate().menuManager.quitItem retain]; break; case typePreferences: - item->item = appDelegate().menuManager.preferencesItem; + item->item = [appDelegate().menuManager.preferencesItem retain]; break; case typeAbout: - item->item = appDelegate().menuManager.aboutItem; + item->item = [appDelegate().menuManager.aboutItem retain]; break; case typeSeparator: - item->item = [NSMenuItem separatorItem]; + item->item = [[NSMenuItem separatorItem] retain]; [m->menu addItem:item->item]; break; default: @@ -335,7 +346,6 @@ void uninitMenus(void) { if (menus == NULL) return; - // don't worry about the actual NSMenus and NSMenuItems; they'll be freed when we clean up the NSApplication [menus enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop) { NSValue *v; uiMenu *m; diff --git a/darwin/uipriv_darwin.h b/darwin/uipriv_darwin.h index 4a8b1bdd..865d3a48 100644 --- a/darwin/uipriv_darwin.h +++ b/darwin/uipriv_darwin.h @@ -89,6 +89,8 @@ extern void mapDestroy(struct mapTable *m); extern void *mapGet(struct mapTable *m, void *key); extern void mapSet(struct mapTable *m, void *key, void *value); extern void mapDelete(struct mapTable *m, void *key); +extern void mapWalk(struct mapTable *m, void (*f)(void *key, void *value)); +extern void mapReset(struct mapTable *m); // area.m extern int sendAreaEvents(NSEvent *);