Skip to content

Deadlock in thunar-tree-view-model.c

Description

thunar_tree_view_model_update_search_files and thunar_tree_view_model_add_search_files can deadlock when the _thunar_return_val_if_fail condition on line 2947 fails:

2934  static gboolean
2935  thunar_tree_view_model_update_search_files (ThunarTreeViewModel *model)
2936  {
2937    ThunarFile *file;
2938    gboolean    matched;
2939    gchar      *name_n;
2940  
2941    g_mutex_lock (&model->mutex_add_search_files);
2942  
2943    for (GList *lp = model->search_files; lp != NULL; lp = lp->next)
2944      {
2945        /* take a reference on that file */
2946        file = THUNAR_FILE (g_object_ref (G_OBJECT (lp->data)));
2947        _thunar_return_val_if_fail (THUNAR_IS_FILE (file), TRUE);

-- https://gitlab.xfce.org/xfce/thunar/-/blob/bbd8f3ea7048c7ef77fef450b4c483551894908f/thunar/thunar-tree-view-model.c#L2934-2947

2970  static void
2971  thunar_tree_view_model_add_search_files (ThunarStandardViewModel *model,
2972                                           GList                   *files)
2973  {
2974    ThunarTreeViewModel *_model = THUNAR_TREE_VIEW_MODEL (model);
2975
2976    g_mutex_lock (&_model->mutex_add_search_files);
2977
2978    _model->search_files = g_list_concat (_model->search_files, files);
2979
2980    g_mutex_unlock (&_model->mutex_add_search_files);
2981  }

-- https://gitlab.xfce.org/xfce/thunar/-/blob/bbd8f3ea7048c7ef77fef450b4c483551894908f/thunar/thunar-tree-view-model.c#L2970-2981

model->search_files can also leak when the condition fails.

Steps to reproduce

  1. mkdir deadlock
  2. touch deadlock/test1
  3. thunar deadlock
  4. In a terminal, run this script from the deadlock directory: while [ 1 ] ; do mv test1 test2; mv test2 test1; sleep .01; done
  5. Ctrl + f in the window
  6. Alternate between searching for t and test until the thunar-CRITICAL triggers and the window freezes

Debug output

(thunar:347116): thunar-CRITICAL **: 22:25:38.616: thunar_tree_view_model_update_search_files: assertion '(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) ((file)); GType __t = ((thunar_file_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; }))))' failed

Stack traces

Thread 21 (Thread 0x7fffdba2d6c0 (LWP 348661) "pool-thunar"):
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ffff6f8e20b in g_mutex_lock_slowpath (mutex=0x50e00004c808) at ../glib/glib/gthread-posix.c:1465
#2  0x0000555555e049c9 in thunar_tree_view_model_add_search_files (model=0x50e00004c780, files=0x50300098e120 = {...}) at thunar-tree-view-model.c:2976
#3  0x0000555555d6ce35 in thunar_standard_view_model_add_search_files (model=0x50e00004c780, files=0x50300098e120 = {...}) at thunar-standard-view-model.c:425
#4  0x0000555555be4f70 in _thunar_search_folder (model=0x50e00004c780, job=0x50e00014abc0, uri=0x50400038a110 "file:///home/s/code/thunar/deadlock", search_query_c_terms=0x50200042a090, search_type=THUNAR_STANDARD_VIEW_MODEL_SEARCH_RECURSIVE, show_hidden=1) at thunar-io-jobs.c:1607
#5  0x0000555555be0482 in _thunar_job_search_directory (job=0x50e00014abc0, param_values=0x504000389110, error=0x7fffda72d020) at thunar-io-jobs.c:1648
#6  0x0000555555d228c6 in thunar_simple_job_execute (job=0x50e00014abc0, error=0x7fffdba2ca88) at thunar-simple-job.c:119
#7  0x00007ffff7f47aec in exo_job_scheduler_job_func (scheduler_job=0x50600036e960, cancellable=0x50600036e860, user_data=0x50e00014abc0) at exo-job.c:310
#8  0x00007ffff70a142e in io_job_thread (task=<optimized out>, source_object=<optimized out>, task_data=0x50600036e960, cancellable=<optimized out>) at ../glib/gio/gioscheduler.c:87
#9  0x00007ffff70d4db8 in g_task_thread_pool_thread (thread_data=0x5100000caa40, pool_data=<optimized out>) at ../glib/gio/gtask.c:1593
#10 0x00007ffff6f69523 in g_thread_pool_thread_proxy (data=<optimized out>) at ../glib/glib/gthreadpool.c:350
#11 0x00007ffff6f66a45 in g_thread_proxy (data=0x5070000106a0) at ../glib/glib/gthread.c:831
#12 0x00005555559145d7 in asan_thread_start(void*) ()
#13 0x00007ffff6d8455a in start_thread (arg=<optimized out>) at pthread_create.c:447
#14 0x00007ffff6e01a3c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Thread 1 (Thread 0x7ffff5863f00 (LWP 347116) "thunar"):
#0  syscall () at ../sysdeps/unix/sysv/linux/x86_64/syscall.S:38
#1  0x00007ffff6f8e20b in g_mutex_lock_slowpath (mutex=0x50e00004c808) at ../glib/glib/gthread-posix.c:1465
#2  0x0000555555dea3cb in thunar_tree_view_model_update_search_files (model=0x50e00004c780, model@entry=<error reading variable: value has been optimized out>) at thunar-tree-view-model.c:2941
#3  0x00007ffff6f363ee in g_timeout_dispatch (source=0x50b00013cb20, callback=<optimized out>, user_data=<optimized out>) at ../glib/glib/gmain.c:5121
#4  0x00007ffff6f34f69 in g_main_dispatch (context=0x50f000000310) at ../glib/glib/gmain.c:3476
#5  0x00007ffff6f933a7 in g_main_context_dispatch_unlocked (context=0x50f000000310) at ../glib/glib/gmain.c:4284
#6  g_main_context_iterate_unlocked.isra.0 (context=context@entry=0x50f000000310, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/glib/gmain.c:4349
#7  0x00007ffff6f33162 in g_main_context_iteration (context=context@entry=0x50f000000310, may_block=may_block@entry=1) at ../glib/glib/gmain.c:4414
#8  0x00007ffff7106b66 in g_application_run (application=0x514000000930, argc=<optimized out>, argv=0x7fffffffe5a8) at ../glib/gio/gapplication.c:2577
#9  0x0000555555a637fc in main (argc=2, argv=0x7fffffffe5a8) at main.c:86

Version: 75c803af