1b5975d6bSopenharmony_ciFrom 222f6ceada3c54cddf1cfa7a3b846716bafe244c Mon Sep 17 00:00:00 2001 2b5975d6bSopenharmony_ciFrom: Benjamin Berg <bberg@redhat.com> 3b5975d6bSopenharmony_ciDate: Fri, 18 Mar 2022 12:16:12 +0100 4b5975d6bSopenharmony_ciSubject: [PATCH 1/3] glocalfilemonitor: Avoid file monitor destruction from 5b5975d6bSopenharmony_ci event thread 6b5975d6bSopenharmony_ci 7b5975d6bSopenharmony_ciTaking a reference to the GFileMonitor when handling events may cause 8b5975d6bSopenharmony_ciobject destruction from th worker thread that calls the function. This 9b5975d6bSopenharmony_cicondition happens if the surrounding code drops the otherwise last 10b5975d6bSopenharmony_cireference ot the GFileMonitor. The series of events causes destruction 11b5975d6bSopenharmony_cifrom an unrelated worker thread and also triggers g_file_monitor_cancel 12b5975d6bSopenharmony_cito be called from g_file_monitor_source_handle_event. 13b5975d6bSopenharmony_ci 14b5975d6bSopenharmony_ciFor the inotify backend, this results in a deadlock as cancellation 15b5975d6bSopenharmony_cineeds to take a lock that protects data structures from being modified 16b5975d6bSopenharmony_ciwhile events are dispatched. 17b5975d6bSopenharmony_ci 18b5975d6bSopenharmony_ciOne alternative to this approach might be to add an RCU (release, copy, 19b5975d6bSopenharmony_ciupdate) approach to the lists contained in the wd_dir_hash and 20b5975d6bSopenharmony_ciwd_file_hash hash tables. 21b5975d6bSopenharmony_ci 22b5975d6bSopenharmony_ciFixes: #1941 23b5975d6bSopenharmony_ci 24b5975d6bSopenharmony_ciAn example stack trace of this happening is: 25b5975d6bSopenharmony_ci 26b5975d6bSopenharmony_ciThread 2 (Thread 0x7fea68b1d640 (LWP 260961) "gmain"): 27b5975d6bSopenharmony_ci #0 syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38 28b5975d6bSopenharmony_ci #1 0x00007fea692215dc in g_mutex_lock_slowpath (mutex=mutex@entry=0x7fea6911e148 <g.inotify_lock_lock>) at ../glib/gthread-posix.c:1493 29b5975d6bSopenharmony_ci #2 0x00007fea69222062 in g_mutex_lock (mutex=mutex@entry=0x7fea6911e148 <g.inotify_lock_lock>) at ../glib/gthread-posix.c:1517 30b5975d6bSopenharmony_ci #3 0x00007fea6908025a in _ih_sub_cancel (sub=0x1492620) at ../gio/inotify/inotify-helper.c:131 31b5975d6bSopenharmony_ci #4 0x00007fea6907f9da in g_inotify_file_monitor_cancel (monitor=0x14a3550) at ../gio/inotify/ginotifyfilemonitor.c:75 32b5975d6bSopenharmony_ci #5 0x00007fea68fae959 in g_file_monitor_cancel (monitor=0x14a3550) at ../gio/gfilemonitor.c:241 33b5975d6bSopenharmony_ci #6 0x00007fea68fae9dc in g_file_monitor_dispose (object=0x14a3550) at ../gio/gfilemonitor.c:123 34b5975d6bSopenharmony_ci #7 0x00007fea69139341 in g_object_unref (_object=<optimized out>) at ../gobject/gobject.c:3636 35b5975d6bSopenharmony_ci #8 g_object_unref (_object=0x14a3550) at ../gobject/gobject.c:3553 36b5975d6bSopenharmony_ci #9 0x00007fea6907507a in g_file_monitor_source_handle_event (fms=0x14c3560, event_type=<optimized out>, child=0x7fea64001460 "spawned-1", rename_to=rename_to@entry=0x0, other=other@entry=0x0, event_time=<optimized out>) at ../gio/glocalfilemonitor.c:457 37b5975d6bSopenharmony_ci #10 0x00007fea6907fe0e in ih_event_callback (event=0x7fea64001420, sub=0x1492620, file_event=<optimized out>) at ../gio/inotify/inotify-helper.c:218 38b5975d6bSopenharmony_ci #11 0x00007fea6908075c in ip_event_dispatch (dir_list=dir_list@entry=0x14c14c0, file_list=0x0, event=event@entry=0x7fea64001420) at ../gio/inotify/inotify-path.c:493 39b5975d6bSopenharmony_ci #12 0x00007fea6908094e in ip_event_dispatch (event=0x7fea64001420, file_list=<optimized out>, dir_list=0x14c14c0) at ../gio/inotify/inotify-path.c:448 40b5975d6bSopenharmony_ci #13 ip_event_callback (event=0x7fea64001420) at ../gio/inotify/inotify-path.c:548 41b5975d6bSopenharmony_ci #14 ip_event_callback (event=0x7fea64001420) at ../gio/inotify/inotify-path.c:530 42b5975d6bSopenharmony_ci #15 0x00007fea69081391 in ik_source_dispatch (source=0x14a2bf0, func=0x7fea69080890 <ip_event_callback>, user_data=<optimized out>) at ../gio/inotify/inotify-kernel.c:327 43b5975d6bSopenharmony_ci #16 0x00007fea691d0824 in g_main_dispatch (context=0x14a2cc0) at ../glib/gmain.c:3417 44b5975d6bSopenharmony_ci #17 g_main_context_dispatch (context=0x14a2cc0) at ../glib/gmain.c:4135 45b5975d6bSopenharmony_ci #18 0x00007fea691d0b88 in g_main_context_iterate (context=context@entry=0x14a2cc0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/gmain.c:4211 46b5975d6bSopenharmony_ci #19 0x00007fea691d0c2f in g_main_context_iteration (context=0x14a2cc0, may_block=may_block@entry=1) at ../glib/gmain.c:4276 47b5975d6bSopenharmony_ci #20 0x00007fea691d0c81 in glib_worker_main (data=<optimized out>) at ../glib/gmain.c:6176 48b5975d6bSopenharmony_ci #21 0x00007fea691f9c2d in g_thread_proxy (data=0x1487cc0) at ../glib/gthread.c:827 49b5975d6bSopenharmony_ci #22 0x00007fea68d93b1a in start_thread (arg=<optimized out>) at pthread_create.c:443 50b5975d6bSopenharmony_ci #23 0x00007fea68e18650 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 51b5975d6bSopenharmony_ci--- 52b5975d6bSopenharmony_ci gio/glocalfilemonitor.c | 14 +++++--------- 53b5975d6bSopenharmony_ci 1 file changed, 5 insertions(+), 9 deletions(-) 54b5975d6bSopenharmony_ci 55b5975d6bSopenharmony_cidiff --git a/gio/glocalfilemonitor.c b/gio/glocalfilemonitor.c 56b5975d6bSopenharmony_ciindex 4f85fea52..f408d0707 100644 57b5975d6bSopenharmony_ci--- a/gio/glocalfilemonitor.c 58b5975d6bSopenharmony_ci+++ b/gio/glocalfilemonitor.c 59b5975d6bSopenharmony_ci@@ -348,7 +348,6 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, 60b5975d6bSopenharmony_ci gint64 event_time) 61b5975d6bSopenharmony_ci { 62b5975d6bSopenharmony_ci gboolean interesting = TRUE; 63b5975d6bSopenharmony_ci- GFileMonitor *instance = NULL; 64b5975d6bSopenharmony_ci 65b5975d6bSopenharmony_ci g_assert (!child || is_basename (child)); 66b5975d6bSopenharmony_ci g_assert (!rename_to || is_basename (rename_to)); 67b5975d6bSopenharmony_ci@@ -359,13 +358,11 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, 68b5975d6bSopenharmony_ci 69b5975d6bSopenharmony_ci g_mutex_lock (&fms->lock); 70b5975d6bSopenharmony_ci 71b5975d6bSopenharmony_ci- /* monitor is already gone -- don't bother */ 72b5975d6bSopenharmony_ci- instance = g_weak_ref_get (&fms->instance_ref); 73b5975d6bSopenharmony_ci- if (instance == NULL) 74b5975d6bSopenharmony_ci- { 75b5975d6bSopenharmony_ci- g_mutex_unlock (&fms->lock); 76b5975d6bSopenharmony_ci- return TRUE; 77b5975d6bSopenharmony_ci- } 78b5975d6bSopenharmony_ci+ /* NOTE: We process events even if the file monitor has already been disposed. 79b5975d6bSopenharmony_ci+ * The reason is that we must not take a reference to the instance here 80b5975d6bSopenharmony_ci+ * as destroying it from the event handling thread will lead to a 81b5975d6bSopenharmony_ci+ * deadlock when taking the lock in _ih_sub_cancel. 82b5975d6bSopenharmony_ci+ */ 83b5975d6bSopenharmony_ci 84b5975d6bSopenharmony_ci switch (event_type) 85b5975d6bSopenharmony_ci { 86b5975d6bSopenharmony_ci@@ -452,7 +449,6 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, 87b5975d6bSopenharmony_ci g_file_monitor_source_update_ready_time (fms); 88b5975d6bSopenharmony_ci 89b5975d6bSopenharmony_ci g_mutex_unlock (&fms->lock); 90b5975d6bSopenharmony_ci- g_clear_object (&instance); 91b5975d6bSopenharmony_ci 92b5975d6bSopenharmony_ci return interesting; 93b5975d6bSopenharmony_ci } 94b5975d6bSopenharmony_ci-- 95b5975d6bSopenharmony_ci2.41.0.windows.3 96b5975d6bSopenharmony_ci 97