xapp-sn-watcher.c: Don't try to use a null pointer as a hash table
lookup key.
When a new item tries to register, its key is added to the item table
with a null value, to prevent trying to register the same client
multiple times. When registration is finished, the key is removed,
and re-used to add the new item to the table.
If the app disappears before that registration finishes, we remove
its key from the table (handle_sn_item_name_owner_lost), so when the
item registration completes (it will because a proxy doesn't need an
owner), our steal/re-add fails because the key was removed already.
This will have us steal the key early when completing registration,
and abort if it's null.
Also wrap g_object_unref when removing an item from the table to
prevent a warning.
Michael Webster
3 years ago
307 | 307 | } NewSnProxyData; |
308 | 308 | |
309 | 309 | static void |
310 | free_sn_proxy_data (NewSnProxyData *data) | |
311 | { | |
312 | g_free (data->key); | |
313 | g_free (data->path); | |
314 | g_free (data->bus_name); | |
315 | g_free (data->service); | |
316 | g_object_unref (data->invocation); | |
317 | ||
318 | g_slice_free (NewSnProxyData, data); | |
319 | } | |
320 | ||
321 | static void | |
310 | 322 | sn_item_proxy_new_completed (GObject *source, |
311 | 323 | GAsyncResult *res, |
312 | 324 | gpointer user_data) |
321 | 333 | |
322 | 334 | proxy = sn_item_interface_proxy_new_finish (res, &error); |
323 | 335 | |
336 | g_hash_table_steal_extended (watcher->items, | |
337 | data->key, | |
338 | &stolen_ptr, | |
339 | NULL); | |
340 | ||
341 | if ((gchar *) stolen_ptr == NULL) | |
342 | { | |
343 | g_dbus_method_invocation_return_error (data->invocation, | |
344 | G_DBUS_ERROR, | |
345 | G_DBUS_ERROR_FAILED, | |
346 | "New StatusNotifierItem disappeared before " | |
347 | "its registration was complete."); | |
348 | ||
349 | free_sn_proxy_data (data); | |
350 | g_clear_object (&proxy); | |
351 | return; | |
352 | } | |
353 | ||
324 | 354 | if (error != NULL) |
325 | 355 | { |
326 | 356 | if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
329 | 359 | data->bus_name, error->message); |
330 | 360 | } |
331 | 361 | |
332 | g_hash_table_steal_extended (watcher->items, | |
333 | data->key, | |
334 | &stolen_ptr, | |
335 | NULL); | |
336 | 362 | g_free (stolen_ptr); |
363 | free_sn_proxy_data (data); | |
337 | 364 | |
338 | 365 | g_dbus_method_invocation_take_error (data->invocation, error); |
339 | 366 | return; |
341 | 368 | |
342 | 369 | item = sn_item_new ((GDBusProxy *) proxy, |
343 | 370 | g_str_has_prefix (data->path, APPINDICATOR_PATH_PREFIX)); |
344 | ||
345 | g_hash_table_steal_extended (watcher->items, | |
346 | data->key, | |
347 | &stolen_ptr, | |
348 | NULL); | |
349 | 371 | |
350 | 372 | g_hash_table_insert (watcher->items, |
351 | 373 | stolen_ptr, |
359 | 381 | sn_watcher_interface_complete_register_status_notifier_item (watcher->skeleton, |
360 | 382 | data->invocation); |
361 | 383 | |
362 | g_free (data->key); | |
363 | g_free (data->path); | |
364 | g_free (data->bus_name); | |
365 | g_free (data->service); | |
366 | g_object_unref (data->invocation); | |
367 | g_slice_free (NewSnProxyData, data); | |
384 | free_sn_proxy_data (data); | |
368 | 385 | } |
369 | 386 | |
370 | 387 | static gboolean |
493 | 510 | } |
494 | 511 | |
495 | 512 | static void |
513 | unref_proxy (gpointer data) | |
514 | { | |
515 | // if g_hash_table_remove is called from handle_sn_item_name_owner_lost | |
516 | // *before* sn_item_proxy_new_completed is complete, the key will be | |
517 | // pointing to a NULL value, so avoid trying to free it. | |
518 | ||
519 | if (data == NULL) | |
520 | { | |
521 | return; | |
522 | } | |
523 | ||
524 | SnItem *item = SN_ITEM (data); | |
525 | ||
526 | if (item) | |
527 | { | |
528 | g_object_unref (item); | |
529 | } | |
530 | } | |
531 | ||
532 | static void | |
496 | 533 | watcher_startup (GApplication *application) |
497 | 534 | { |
498 | 535 | XAppSnWatcher *watcher = (XAppSnWatcher*) application; |
503 | 540 | xapp_settings = g_settings_new (STATUS_ICON_SCHEMA); |
504 | 541 | |
505 | 542 | watcher->items = g_hash_table_new_full (g_str_hash, g_str_equal, |
506 | g_free, g_object_unref); | |
543 | g_free, (GDestroyNotify) unref_proxy); | |
507 | 544 | |
508 | 545 | /* This buys us 30 seconds (gapp timeout) - we'll either be re-held immediately |
509 | 546 | * because there's a monitor or exit after the 30 seconds. */ |