Hello community, here is the log from the commit of package libdazzle for openSUSE:Factory checked in at 2018-02-03 15:39:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libdazzle (Old) and /work/SRC/openSUSE:Factory/.libdazzle.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libdazzle" Sat Feb 3 15:39:26 2018 rev:5 rq:572090 version:3.26.3 Changes: -------- --- /work/SRC/openSUSE:Factory/libdazzle/libdazzle.changes 2018-01-25 12:38:07.901411161 +0100 +++ /work/SRC/openSUSE:Factory/.libdazzle.new/libdazzle.changes 2018-02-03 15:39:27.749890634 +0100 @@ -1,0 +2,17 @@ +Fri Feb 2 10:28:51 UTC 2018 - [email protected] + +- Update to vresion 3.26.3: + + A number of fixes to DzlSignalGroup to be more re-entrant safe + and handle disposal cycles better. + + DzlPreferences is more aggressive about protecting against + widget disposal. + + A static inline dzl_clear_signal_handler() was backported for + use in other backports from master. + + A number of protections were added to DzlDirectoryReaper to + protect against potentially following through symlinks. + + Max age in DzlDirectoryReaper was changed to always ensure a + positive value for use in date comparisons. + + A leak of GFile instances in the directory reaper was fixed. +- Drop unused base define. + +------------------------------------------------------------------- Old: ---- libdazzle-3.26.2.tar.xz New: ---- libdazzle-3.26.3.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libdazzle.spec ++++++ --- /var/tmp/diff_new_pack.KeSs2R/_old 2018-02-03 15:39:28.429858874 +0100 +++ /var/tmp/diff_new_pack.KeSs2R/_new 2018-02-03 15:39:28.433858688 +0100 @@ -16,9 +16,8 @@ # -%define base 3.25 Name: libdazzle -Version: 3.26.2 +Version: 3.26.3 Release: 0 Summary: Collection of fancy features for GLib and Gtk+ License: GPL-3.0+ AND LGPL-2.1+ ++++++ libdazzle-3.26.2.tar.xz -> libdazzle-3.26.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/NEWS new/libdazzle-3.26.3/NEWS --- old/libdazzle-3.26.2/NEWS 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/NEWS 2018-02-01 00:00:27.000000000 +0100 @@ -1,4 +1,24 @@ ============== +Version 3.26.3 +============== + +Changes in this release: + + • A number of fixes to DzlSignalGroup to be more re-entrant safe + and handle disposal cycles better. + • DzlPreferences is more aggressive about protecting against + widget disposal. + • A static inline dzl_clear_signal_handler() was backported for + use in other backports from master. + • A number of protections were added to DzlDirectoryReaper to + protect against potentially following through symlinks. + • Max age in DzlDirectoryReaper was changed to always ensure + a positive value for use in date comparisons. + • A leak of GFile instances in the directory reaper was fixed. + +It's recommended that all distributions update to this release. + +============== Version 3.26.2 ============== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/meson.build new/libdazzle-3.26.3/meson.build --- old/libdazzle-3.26.2/meson.build 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/meson.build 2018-02-01 00:00:27.000000000 +0100 @@ -1,5 +1,5 @@ project('libdazzle', 'c', - version: '3.26.2', + version: '3.26.3', license: 'GPLv3+', meson_version: '>= 0.40.1', default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/src/bindings/dzl-signal-group.c new/libdazzle-3.26.3/src/bindings/dzl-signal-group.c --- old/libdazzle-3.26.2/src/bindings/dzl-signal-group.c 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/src/bindings/dzl-signal-group.c 2018-02-01 00:00:27.000000000 +0100 @@ -52,10 +52,12 @@ { GObject parent_instance; - GObject *target; + GWeakRef target_ref; GPtrArray *handlers; GType target_type; gsize block_count; + + guint has_bound_at_least_once : 1; }; struct _DzlSignalGroupClass @@ -71,7 +73,6 @@ DzlSignalGroup *group; gulong handler_id; GClosure *closure; - GObject *object; guint signal_id; GQuark signal_detail; guint connect_after : 1; @@ -120,71 +121,64 @@ } static void -dzl_signal_group__target_weak_notify (gpointer data, - GObject *where_object_was) +dzl_signal_group_gc_handlers (DzlSignalGroup *self) { - DzlSignalGroup *self = data; - gsize i; - g_assert (DZL_IS_SIGNAL_GROUP (self)); - g_assert (where_object_was != NULL); - g_assert (self->target == where_object_was); - for (i = 0; i < self->handlers->len; i++) - { - SignalHandler *handler; + /* + * Remove any handlers for which the closures have become invalid. We do + * this cleanup lazily to avoid situations where we could have disposal + * active on both the signal group and the peer object. + */ - handler = g_ptr_array_index (self->handlers, i); - handler->handler_id = 0; - } + for (guint i = self->handlers->len; i > 0; i--) + { + const SignalHandler *handler = g_ptr_array_index (self->handlers, i - 1); - self->target = NULL; + g_assert (handler != NULL); + g_assert (handler->closure != NULL); - g_signal_emit (self, signals [UNBIND], 0); - g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TARGET]); + if (handler->closure->is_invalid) + g_ptr_array_remove_index (self->handlers, i - 1); + } } static void -dzl_signal_group__connect_object_weak_notify (gpointer data, - GObject *where_object_was) +dzl_signal_group__target_weak_notify (gpointer data, + GObject *where_object_was) { DzlSignalGroup *self = data; - gsize i; g_assert (DZL_IS_SIGNAL_GROUP (self)); g_assert (where_object_was != NULL); - for (i = 0; i < self->handlers->len; ++i) - { - SignalHandler *handler; + g_weak_ref_set (&self->target_ref, NULL); - handler = g_ptr_array_index (self->handlers, i); + for (guint i = 0; i < self->handlers->len; i++) + { + SignalHandler *handler = g_ptr_array_index (self->handlers, i); - if (handler->object == where_object_was) - { - handler->object = NULL; - g_ptr_array_remove_index_fast (self->handlers, i); - return; - } + handler->handler_id = 0; } - g_critical ("Failed to find handler for %p", (void *)where_object_was); + g_signal_emit (self, signals [UNBIND], 0); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TARGET]); } static void dzl_signal_group_bind_handler (DzlSignalGroup *self, - SignalHandler *handler) + SignalHandler *handler, + GObject *target) { - gsize i; - g_assert (self != NULL); - g_assert (self->target != NULL); + g_assert (G_IS_OBJECT (target)); g_assert (handler != NULL); g_assert (handler->signal_id != 0); g_assert (handler->closure != NULL); + g_assert (handler->closure->is_invalid == 0); g_assert (handler->handler_id == 0); - handler->handler_id = g_signal_connect_closure_by_id (self->target, + handler->handler_id = g_signal_connect_closure_by_id (target, handler->signal_id, handler->signal_detail, handler->closure, @@ -192,63 +186,75 @@ g_assert (handler->handler_id != 0); - for (i = 0; i < self->block_count; i++) - g_signal_handler_block (self->target, handler->handler_id); + for (guint i = 0; i < self->block_count; i++) + g_signal_handler_block (target, handler->handler_id); } static void dzl_signal_group_bind (DzlSignalGroup *self, GObject *target) { - gsize i; + g_autoptr(GObject) hold = NULL; g_assert (DZL_IS_SIGNAL_GROUP (self)); - g_assert (self->target == NULL); g_assert (!target || G_IS_OBJECT (target)); if (target == NULL) return; - self->target = target; - g_object_weak_ref (self->target, - dzl_signal_group__target_weak_notify, - self); + self->has_bound_at_least_once = TRUE; + + hold = g_object_ref (target); - g_object_ref (target); + g_weak_ref_set (&self->target_ref, hold); + g_object_weak_ref (hold, dzl_signal_group__target_weak_notify, self); - for (i = 0; i < self->handlers->len; i++) + dzl_signal_group_gc_handlers (self); + + for (guint i = 0; i < self->handlers->len; i++) { - SignalHandler *handler; + SignalHandler *handler = g_ptr_array_index (self->handlers, i); - handler = g_ptr_array_index (self->handlers, i); - dzl_signal_group_bind_handler (self, handler); + dzl_signal_group_bind_handler (self, handler, hold); } - g_signal_emit (self, signals [BIND], 0, target); - g_object_unref (target); + g_signal_emit (self, signals [BIND], 0, hold); } static void dzl_signal_group_unbind (DzlSignalGroup *self) { - GObject *target; - gsize i; + g_autoptr(GObject) target = NULL; g_return_if_fail (DZL_IS_SIGNAL_GROUP (self)); - if (self->target == NULL) - return; + target = g_weak_ref_get (&self->target_ref); - target = self->target; - self->target = NULL; + /* + * Target may be NULL by this point, as we got notified of its destruction. + * However, if we're early enough, we may get a full reference back and can + * cleanly disconnect our connections. + */ + + if (target != NULL) + { + g_weak_ref_set (&self->target_ref, NULL); + + /* + * Let go of our weak reference now that we have a full reference + * for the life of this function. + */ + g_object_weak_unref (target, + dzl_signal_group__target_weak_notify, + self); + } - g_object_weak_unref (target, - dzl_signal_group__target_weak_notify, - self); + dzl_signal_group_gc_handlers (self); - for (i = 0; i < self->handlers->len; i++) + for (guint i = 0; i < self->handlers->len; i++) { SignalHandler *handler; + gulong handler_id; handler = g_ptr_array_index (self->handlers, i); @@ -256,15 +262,17 @@ g_assert (handler->signal_id != 0); g_assert (handler->closure != NULL); - if (handler->handler_id != 0) - { - gulong handler_id; + handler_id = handler->handler_id; + handler->handler_id = 0; - handler_id = handler->handler_id; - handler->handler_id = 0; + /* + * If @target is NULL, we lost a race to cleanup the weak + * instance and the signal connections have already been + * finalized and therefore nothing to do. + */ - g_signal_handler_disconnect (target, handler_id); - } + if (target != NULL && handler_id != 0) + g_signal_handler_disconnect (target, handler_id); } g_signal_emit (self, signals [UNBIND], 0); @@ -302,28 +310,28 @@ void dzl_signal_group_block (DzlSignalGroup *self) { - gsize i; + g_autoptr(GObject) target = NULL; g_return_if_fail (DZL_IS_SIGNAL_GROUP (self)); g_return_if_fail (self->block_count != G_MAXSIZE); self->block_count++; - if (self->target == NULL) + target = g_weak_ref_get (&self->target_ref); + + if (target == NULL) return; - for (i = 0; i < self->handlers->len; i++) + for (guint i = 0; i < self->handlers->len; i++) { - SignalHandler *handler; - - handler = g_ptr_array_index (self->handlers, i); + const SignalHandler *handler = g_ptr_array_index (self->handlers, i); g_assert (handler != NULL); g_assert (handler->signal_id != 0); g_assert (handler->closure != NULL); g_assert (handler->handler_id != 0); - g_signal_handler_block (self->target, handler->handler_id); + g_signal_handler_block (target, handler->handler_id); } } @@ -341,28 +349,28 @@ void dzl_signal_group_unblock (DzlSignalGroup *self) { - gsize i; + g_autoptr(GObject) target = NULL; g_return_if_fail (DZL_IS_SIGNAL_GROUP (self)); g_return_if_fail (self->block_count != 0); self->block_count--; - if (self->target == NULL) + target = g_weak_ref_get (&self->target_ref); + + if (target == NULL) return; - for (i = 0; i < self->handlers->len; i++) + for (guint i = 0; i < self->handlers->len; i++) { - SignalHandler *handler; - - handler = g_ptr_array_index (self->handlers, i); + const SignalHandler *handler = g_ptr_array_index (self->handlers, i); g_assert (handler != NULL); g_assert (handler->signal_id != 0); g_assert (handler->closure != NULL); g_assert (handler->handler_id != 0); - g_signal_handler_unblock (self->target, handler->handler_id); + g_signal_handler_unblock (target, handler->handler_id); } } @@ -377,9 +385,27 @@ gpointer dzl_signal_group_get_target (DzlSignalGroup *self) { + g_autoptr(GObject) target = NULL; + g_return_val_if_fail (DZL_IS_SIGNAL_GROUP (self), NULL); - return (gpointer)self->target; + target = g_weak_ref_get (&self->target_ref); + + /* + * It is expected that this is called from a thread that owns a reference to + * the target, so we can pass back a borrowed reference. However, to ensure + * that we aren't racing in finalization of @target, we must ensure that the + * ref_count >= 2 (as our get just incremented by one). + */ + + if (target == NULL || target->ref_count < 2) + return NULL; + + /* Unref and pass back a borrowed reference. This looks unsafe, but is safe + * because of our reference check above, so much as the assertion holds that + * the caller obeyed the ownership rules of this class. + */ + return target; } /** @@ -399,16 +425,24 @@ dzl_signal_group_set_target (DzlSignalGroup *self, gpointer target) { + g_autoptr(GObject) object = NULL; + g_return_if_fail (DZL_IS_SIGNAL_GROUP (self)); - if (target == (gpointer)self->target) + object = g_weak_ref_get (&self->target_ref); + + if (object == (GObject *)target) return; if (!dzl_signal_group_check_target_type (self, target)) return; - dzl_signal_group_unbind (self); + /* Only emit unbind if we've ever called bind */ + if (self->has_bound_at_least_once) + dzl_signal_group_unbind (self); + dzl_signal_group_bind (self, target); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TARGET]); } @@ -417,18 +451,13 @@ { SignalHandler *handler = data; - if (handler->object != NULL) - { - g_object_weak_unref (handler->object, - dzl_signal_group__connect_object_weak_notify, - handler->group); - handler->object = NULL; - } + if (handler->closure != NULL) + g_closure_invalidate (handler->closure); - g_clear_pointer (&handler->closure, g_closure_unref); handler->handler_id = 0; handler->signal_id = 0; handler->signal_detail = 0; + g_clear_pointer (&handler->closure, g_closure_unref); g_slice_free (SignalHandler, handler); } @@ -436,8 +465,9 @@ dzl_signal_group_constructed (GObject *object) { DzlSignalGroup *self = (DzlSignalGroup *)object; + g_autoptr(GObject) target = g_weak_ref_get (&self->target_ref); - if (!dzl_signal_group_check_target_type (self, self->target)) + if (!dzl_signal_group_check_target_type (self, target)) dzl_signal_group_set_target (self, NULL); G_OBJECT_CLASS (dzl_signal_group_parent_class)->constructed (object); @@ -448,13 +478,27 @@ { DzlSignalGroup *self = (DzlSignalGroup *)object; - dzl_signal_group_unbind (self); + dzl_signal_group_gc_handlers (self); + + if (self->has_bound_at_least_once) + dzl_signal_group_unbind (self); + g_clear_pointer (&self->handlers, g_ptr_array_unref); G_OBJECT_CLASS (dzl_signal_group_parent_class)->dispose (object); } static void +dzl_signal_group_finalize (GObject *object) +{ + DzlSignalGroup *self = (DzlSignalGroup *)object; + + g_weak_ref_clear (&self->target_ref); + + G_OBJECT_CLASS (dzl_signal_group_parent_class)->finalize (object); +} + +static void dzl_signal_group_get_property (GObject *object, guint prop_id, GValue *value, @@ -465,7 +509,7 @@ switch (prop_id) { case PROP_TARGET: - g_value_set_object (value, dzl_signal_group_get_target (self)); + g_value_take_object (value, g_weak_ref_get (&self->target_ref)); break; case PROP_TARGET_TYPE: @@ -507,6 +551,7 @@ object_class->constructed = dzl_signal_group_constructed; object_class->dispose = dzl_signal_group_dispose; + object_class->finalize = dzl_signal_group_finalize; object_class->get_property = dzl_signal_group_get_property; object_class->set_property = dzl_signal_group_set_property; @@ -520,7 +565,7 @@ "Target", "The target instance used when connecting signals.", G_TYPE_OBJECT, - (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); /** * DzlSignalGroup:target-type @@ -610,6 +655,7 @@ GConnectFlags flags, gboolean is_object) { + g_autoptr(GObject) target = NULL; SignalHandler *handler; GClosure *closure; guint signal_id; @@ -620,6 +666,7 @@ g_return_if_fail (g_signal_parse_name (detailed_signal, self->target_type, &signal_id, &signal_detail, TRUE) != 0); g_return_if_fail (callback != NULL); + g_return_if_fail (!is_object || G_IS_OBJECT (data)); if ((flags & G_CONNECT_SWAPPED) != 0) closure = g_cclosure_new_swap (callback, data, notify); @@ -637,19 +684,21 @@ if (is_object) { - /* This is what g_cclosure_new_object() does */ + /* Set closure->is_invalid when data is disposed. We only track this to avoid + * reconnecting in the future. However, we do a round of cleanup when ever we + * connect a new object or the target changes to GC the old handlers. + */ g_object_watch_closure (data, closure); - - handler->object = data; - g_object_weak_ref (data, - dzl_signal_group__connect_object_weak_notify, - self); } g_ptr_array_add (self->handlers, handler); - if (self->target != NULL) - dzl_signal_group_bind_handler (self, handler); + target = g_weak_ref_get (&self->target_ref); + if (target != NULL) + dzl_signal_group_bind_handler (self, handler, target); + + /* Lazily remove any old handlers on connect */ + dzl_signal_group_gc_handlers (self); } /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/src/files/dzl-directory-reaper.c new/libdazzle-3.26.3/src/files/dzl-directory-reaper.c --- old/libdazzle-3.26.2/src/files/dzl-directory-reaper.c 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/src/files/dzl-directory-reaper.c 2018-02-01 00:00:27.000000000 +0100 @@ -121,7 +121,7 @@ glob = "*"; p.type = PATTERN_GLOB; - p.min_age = min_age; + p.min_age = ABS (min_age); p.glob.directory = g_object_ref (directory); p.glob.glob = g_strdup (glob); @@ -139,7 +139,7 @@ g_return_if_fail (G_IS_FILE (file)); p.type = PATTERN_FILE; - p.min_age = min_age; + p.min_age = ABS (min_age); p.file.file = g_object_ref (file); g_array_append_val (self->patterns, p); @@ -168,6 +168,7 @@ g_debug ("Removing uri recursively \"%s\"", uri); enumerator = g_file_enumerate_children (file, + G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK"," G_FILE_ATTRIBUTE_STANDARD_NAME"," G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_TIME_MODIFIED, @@ -189,10 +190,10 @@ while (NULL != (infoptr = g_file_enumerator_next_file (enumerator, cancellable, &enum_error))) { g_autoptr(GFileInfo) info = infoptr; - const gchar *name = g_file_info_get_name (info); - GFile *child = g_file_get_child (file, name); + g_autoptr(GFile) child = g_file_enumerator_get_child (enumerator, info); + GFileType file_type = g_file_info_get_file_type (info); - if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) + if (!g_file_info_get_is_symlink (info) && file_type == G_FILE_TYPE_DIRECTORY) { if (!remove_directory_with_children (child, cancellable, error)) return FALSE; @@ -278,7 +279,9 @@ } enumerator = g_file_enumerate_children (p->glob.directory, + G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK"," G_FILE_ATTRIBUTE_STANDARD_NAME"," + G_FILE_ATTRIBUTE_STANDARD_TYPE"," G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, @@ -293,9 +296,6 @@ while (NULL != (info = g_file_enumerator_next_file (enumerator, cancellable, NULL))) { - const gchar *name; - - name = g_file_info_get_name (info); v64 = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED); /* mtime is in seconds */ @@ -303,21 +303,27 @@ if (v64 < now - p->min_age) { - g_autoptr(GFile) file = g_file_get_child (p->glob.directory, name); + g_autoptr(GFile) file = g_file_enumerator_get_child (enumerator, info); + GFileType file_type = g_file_info_get_file_type (info); - if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable) == G_FILE_TYPE_DIRECTORY) + if (g_file_info_get_is_symlink (info) || file_type != G_FILE_TYPE_DIRECTORY) { - if (!remove_directory_with_children (file, cancellable, &error) || - !g_file_delete (file, cancellable, &error)) + if (!g_file_delete (file, cancellable, &error)) { g_warning ("%s", error->message); g_clear_error (&error); } } - else if (!g_file_delete (file, cancellable, &error)) + else { - g_warning ("%s", error->message); - g_clear_error (&error); + g_assert (file_type == G_FILE_TYPE_DIRECTORY); + + if (!remove_directory_with_children (file, cancellable, &error) || + !g_file_delete (file, cancellable, &error)) + { + g_warning ("%s", error->message); + g_clear_error (&error); + } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/src/prefs/dzl-preferences-view.c new/libdazzle-3.26.3/src/prefs/dzl-preferences-view.c --- old/libdazzle-3.26.2/src/prefs/dzl-preferences-view.c 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/src/prefs/dzl-preferences-view.c 2018-02-01 00:00:27.000000000 +0100 @@ -63,10 +63,19 @@ TrackedWidget *tracked = data; if (tracked->widget != NULL) - g_signal_handler_disconnect (tracked->widget, tracked->handler); + { + dzl_clear_signal_handler (tracked->widget, &tracked->handler); + tracked->widget = NULL; + } + + tracked->handler = 0; + tracked->id = 0; + g_slice_free (TrackedWidget, tracked); } +G_DEFINE_AUTOPTR_CLEANUP_FUNC (TrackedWidget, tracked_widget_free) + static void dzl_preferences_view_track (DzlPreferencesView *self, guint id, @@ -849,10 +858,10 @@ { DzlPreferencesView *self = (DzlPreferencesView *)preferences; DzlPreferencesViewPrivate *priv = dzl_preferences_view_get_instance_private (self); - TrackedWidget *tracked; + g_autoptr(TrackedWidget) tracked = NULL; g_assert (DZL_IS_PREFERENCES_VIEW (self)); - g_assert (widget_id); + g_assert (widget_id != 0); tracked = g_hash_table_lookup (priv->widgets, GUINT_TO_POINTER (widget_id)); @@ -860,7 +869,10 @@ { GtkWidget *widget = tracked->widget; - g_hash_table_remove (priv->widgets, GUINT_TO_POINTER (widget_id)); + /* We have to steal the structure so that we retain access to + * the structure after removing it from the hashtable. + */ + g_hash_table_steal (priv->widgets, GUINT_TO_POINTER (widget_id)); if (widget != NULL && !gtk_widget_in_destruction (widget)) { @@ -871,9 +883,9 @@ gtk_widget_destroy (parent); else gtk_widget_destroy (widget); - - return TRUE; } + + return TRUE; } return FALSE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/src/util/dzl-macros.h new/libdazzle-3.26.3/src/util/dzl-macros.h --- old/libdazzle-3.26.2/src/util/dzl-macros.h 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/src/util/dzl-macros.h 2018-02-01 00:00:27.000000000 +0100 @@ -37,6 +37,18 @@ #define dzl_set_weak_pointer(ptr,obj) \ ((obj!=*(ptr))?(dzl_clear_weak_pointer(ptr),*(ptr)=obj,((obj)?g_object_add_weak_pointer((GObject*)obj,(gpointer*)ptr),NULL:NULL),1):0) +static inline void +dzl_clear_signal_handler (gpointer object, + gulong *location_of_handler) +{ + if (*location_of_handler != 0) + { + gulong handler = *location_of_handler; + *location_of_handler = 0; + g_signal_handler_disconnect (object, handler); + } +} + static inline gboolean dzl_str_empty0 (const gchar *str) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libdazzle-3.26.2/tests/test-directory-reaper.c new/libdazzle-3.26.3/tests/test-directory-reaper.c --- old/libdazzle-3.26.2/tests/test-directory-reaper.c 2018-01-11 02:10:36.000000000 +0100 +++ new/libdazzle-3.26.3/tests/test-directory-reaper.c 2018-02-01 00:00:27.000000000 +0100 @@ -69,6 +69,15 @@ g_assert_cmpint (r, ==, TRUE); } + /* Add a symlink to ../ so that we keep ourselves honest ;) */ + { + g_autofree gchar *cwd = g_get_current_dir (); + g_autofree gchar *name = g_build_filename ("reaper", "parent-link", NULL); + + if (symlink (cwd, name) != 0) + g_error ("Failed to create symlink"); + } + dzl_directory_reaper_add_directory (reaper, file, 0); r = dzl_directory_reaper_execute (reaper, NULL, &error);
