From 1ad25dfb812f53d1b288d0816b1d0d85c1d24d9f Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Fri, 14 Sep 2012 15:18:33 +0200 Subject: [PATCH] quartz: Bug 674108 - Hard crash due to wrong NSAutoreleasePool stacking Apply patch from Kristian Rietveld which addresses two issues in gdkeventloop-quartz.c: This patch moves the autorelease pool drain and introduces protection against the invalidated ufds. Basically, when we suspect ufds has been invalidated by a recursive main loop instance, we refrain from calling the collect function. (cherry picked from commit 79b3326eaab18b942bd7e03ae8d24544182cb3dd) --- gdk/quartz/gdkeventloop-quartz.c | 45 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/gdk/quartz/gdkeventloop-quartz.c b/gdk/quartz/gdkeventloop-quartz.c index 4045234ee..479cd72a7 100644 --- a/gdk/quartz/gdkeventloop-quartz.c +++ b/gdk/quartz/gdkeventloop-quartz.c @@ -635,21 +635,6 @@ gdk_event_check (GSource *source) gdk_threads_enter (); - /* Refresh the autorelease pool if we're at the base CFRunLoop level - * (indicated by current_loop_level) and the base g_main_loop level - * (indicated by g_main_depth()). Messing with the autorelease pool at - * any level of nesting can cause access to deallocated memory because - * autorelease_pool is static and releasing a pool will cause all pools - * allocated inside of it to be released as well. - */ - if (current_loop_level == 0 && g_main_depth() == 0) - { - if (autorelease_pool) - [autorelease_pool drain]; - - autorelease_pool = [[NSAutoreleasePool alloc] init]; - } - retval = (_gdk_event_queue_find_first (_gdk_display) != NULL || _gdk_quartz_event_loop_check_pending ()); @@ -667,6 +652,21 @@ gdk_event_dispatch (GSource *source, gdk_threads_enter (); + /* Refresh the autorelease pool if we're at the base CFRunLoop level + * (indicated by current_loop_level) and the base g_main_loop level + * (indicated by g_main_depth()). Messing with the autorelease pool at + * any level of nesting can cause access to deallocated memory because + * autorelease_pool is static and releasing a pool will cause all pools + * allocated inside of it to be released as well. + */ + if (current_loop_level == 0 && g_main_depth() == 0) + { + if (autorelease_pool) + [autorelease_pool drain]; + + autorelease_pool = [[NSAutoreleasePool alloc] init]; + } + _gdk_quartz_display_queue_events (_gdk_display); event = _gdk_event_unqueue (_gdk_display); @@ -703,6 +703,10 @@ poll_func (GPollFD *ufds, NSDate *limit_date; gint n_ready; + static GPollFD *last_ufds; + + last_ufds = ufds; + n_ready = select_thread_start_poll (ufds, nfds, timeout_); if (n_ready > 0) timeout_ = 0; @@ -721,7 +725,16 @@ poll_func (GPollFD *ufds, dequeue: YES]; getting_events--; - if (n_ready < 0) + /* We check if last_ufds did not change since the time this function was + * called. It is possible that a recursive main loop (and thus recursive + * invocation of this poll function) is triggered while in + * nextEventMatchingMask:. If during that time new fds are added, + * the cached fds array might be replaced in g_main_context_iterate(). + * So, we should avoid accessing the old fd array (still pointed at by + * ufds) here in that case, since it might have been freed. We avoid this + * by not calling the collect stage. + */ + if (last_ufds == ufds && n_ready < 0) n_ready = select_thread_collect_poll (ufds, nfds); if (event && -- 2.43.2