+Overview of changes in GLib 2.60.7
+==================================
+
+* Bugs fixed:
+ - #1819 Invalid characters in Open Location dialog crashes GIMP
+ - #1847 Setting GLIB_VERSION_{MIN_REQUIRED, MAX_ALLOWED} to before 2.56 triggers warnings
+ - !1012 Backport !1009 “gapplication: remove inactivity_timeout source on finalize” to glib-2-60
+ - !1013 Backport !1008 “gmessages: Only use structured logs if GLIB_VERSION_MAX_ALLOWED is ≥2.56” to glib-2-60
+ - !1061 Backport !966 “Resolve "Invalid characters in Open Location dialog crashes GIMP"” to glib-2-60
+ - !1065 Backport !1040 “GSettingsBackend - Fix thread-safety during destruction of GSettings instances...” to glib-2-60
+ - !1081 Backport !1017 “gdatetime: Avoid an assertion failure when parsing some ISO 8601 dates” to glib-2-60
+
+
Overview of changes in GLib 2.60.6
==================================
{
GApplication *application = G_APPLICATION (object);
+ if (application->priv->inactivity_timeout_id)
+ g_source_remove (application->priv->inactivity_timeout_id);
+
g_slist_free_full (application->priv->option_groups, (GDestroyNotify) g_option_group_unref);
if (application->priv->main_options)
g_option_group_unref (application->priv->main_options);
struct _GSettingsBackendWatch
{
- GObject *target;
+ /* Always access the target via the weak reference */
+ GWeakRef target;
+ /* The pointer is only for comparison from the weak notify,
+ * at which point the target might already be close to
+ * destroyed. It's not safe to use it for anything anymore
+ * at that point */
+ GObject *target_ptr;
const GSettingsListenerVTable *vtable;
GMainContext *context;
GSettingsBackendWatch *next;
gchar **names);
GMainContext *context;
- GWeakRef *target_ref;
+ GObject *target;
GSettingsBackend *backend;
gchar *name;
gpointer origin_tag;
/* search and remove */
g_mutex_lock (&backend->priv->lock);
for (ptr = &backend->priv->watches; *ptr; ptr = &(*ptr)->next)
- if ((*ptr)->target == where_the_object_was)
+ if ((*ptr)->target_ptr == where_the_object_was)
{
GSettingsBackendWatch *tmp = *ptr;
*ptr = tmp->next;
+ g_weak_ref_clear (&tmp->target);
g_slice_free (GSettingsBackendWatch, tmp);
g_mutex_unlock (&backend->priv->lock);
* GSettings object in a thread other than the one that is doing the
* dispatching is as follows:
*
- * 1) hold a thread-safe GWeakRef on the GSettings during an outstanding
+ * 1) hold a strong reference on the GSettings during an outstanding
* dispatch. This ensures that the delivery is always possible while
- * the GSettings object is alive.
+ * the GSettings object is alive, and if this was the last reference
+ * then it will be dropped from the dispatch thread.
*
* 2) hold a weak reference on the GSettings at other times. This
* allows us to receive early notification of pending destruction
watch = g_slice_new (GSettingsBackendWatch);
watch->context = context;
watch->vtable = vtable;
- watch->target = target;
+ g_weak_ref_init (&watch->target, target);
+ watch->target_ptr = target;
g_object_weak_ref (target, g_settings_backend_watch_weak_notify, backend);
/* linked list prepend */
g_settings_backend_invoke_closure (gpointer user_data)
{
GSettingsBackendClosure *closure = user_data;
- GObject *target = g_weak_ref_get (closure->target_ref);
- if (target)
- {
- closure->function (target, closure->backend, closure->name,
- closure->origin_tag, closure->names);
- g_object_unref (target);
- }
+ closure->function (closure->target, closure->backend, closure->name,
+ closure->origin_tag, closure->names);
if (closure->context)
g_main_context_unref (closure->context);
g_object_unref (closure->backend);
- g_weak_ref_clear (closure->target_ref);
- g_free (closure->target_ref);
+ g_object_unref (closure->target);
g_strfreev (closure->names);
g_free (closure->name);
for (watch = backend->priv->watches; watch; watch = watch->next)
{
GSettingsBackendClosure *closure;
+ GObject *target = g_weak_ref_get (&watch->target);
+
+ /* If the target was destroyed in the meantime, just skip it here */
+ if (!target)
+ continue;
closure = g_slice_new (GSettingsBackendClosure);
closure->context = watch->context;
if (closure->context)
g_main_context_ref (closure->context);
closure->backend = g_object_ref (backend);
- closure->target_ref = g_new (GWeakRef, 1);
- g_weak_ref_init (closure->target_ref, watch->target);
+ closure->target = g_steal_pointer (&target);
closure->function = G_STRUCT_MEMBER (void *, watch->vtable,
function_offset);
closure->name = g_strdup (name);
const char *uri)
{
GVfsClass *class;
- GFile *ret;
+ GFile *ret = NULL;
g_return_val_if_fail (G_IS_VFS (vfs), NULL);
g_return_val_if_fail (uri != NULL, NULL);
class = G_VFS_GET_CLASS (vfs);
ret = get_file_for_uri_internal (vfs, uri);
- if (ret)
- return ret;
+ if (!ret)
+ ret = (* class->get_file_for_uri) (vfs, uri);
+
+ g_assert (ret != NULL);
- return (* class->get_file_for_uri) (vfs, uri);
+ return g_steal_pointer (&ret);
}
/**
* @vfs: GWinHttpVfs to use
* @uri: URI of the GWinHttpFile to create.
*
- * Returns: new winhttp #GFile.
+ * Returns: (nullable): new winhttp #GFile, or %NULL if there was an error constructing it.
*/
GFile *
_g_winhttp_file_new (GWinHttpVfs *vfs,
{
GWinHttpVfs *winhttp_vfs = G_WINHTTP_VFS (vfs);
int i;
+ GFile *ret = NULL;
/* If it matches one of "our" schemes, handle it */
for (i = 0; i < G_N_ELEMENTS (winhttp_uri_schemes); i++)
- if (g_ascii_strncasecmp (uri, winhttp_uri_schemes[i], strlen (winhttp_uri_schemes[i])) == 0 &&
- uri[strlen (winhttp_uri_schemes[i])] == ':')
- return _g_winhttp_file_new (winhttp_vfs, uri);
+ {
+ if (g_ascii_strncasecmp (uri, winhttp_uri_schemes[i], strlen (winhttp_uri_schemes[i])) == 0 &&
+ uri[strlen (winhttp_uri_schemes[i])] == ':')
+ {
+ ret = _g_winhttp_file_new (winhttp_vfs, uri);
+ }
+ }
/* For other URIs fallback to the wrapped GVfs */
- return g_vfs_get_file_for_uri (winhttp_vfs->wrapped_vfs, uri);
+ if (ret == NULL)
+ ret = g_vfs_get_file_for_uri (winhttp_vfs->wrapped_vfs, uri);
+
+ g_assert (ret != NULL);
+
+ return g_steal_pointer (&ret);
}
static const gchar * const *
tz = g_time_zone_new (text + i);
/* Double-check that the GTimeZone matches our interpretation of the timezone.
- * Failure would indicate a bug either here of in the GTimeZone code. */
- g_assert (g_time_zone_get_offset (tz, 0) == offset_sign * (offset_hours * 3600 + offset_minutes * 60));
+ * This can fail because our interpretation is less strict than (for example)
+ * parse_time() in gtimezone.c, which restricts the range of the parsed
+ * integers. */
+ if (g_time_zone_get_offset (tz, 0) != offset_sign * (offset_hours * 3600 + offset_minutes * 60))
+ {
+ g_time_zone_unref (tz);
+ return NULL;
+ }
return tz;
}
#endif /* G_LOG_DOMAIN */
#if defined(G_HAVE_ISO_VARARGS) && !G_ANALYZER_ANALYZING
-#ifdef G_LOG_USE_STRUCTURED
+#if defined(G_LOG_USE_STRUCTURED) && GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_56
#define g_error(...) G_STMT_START { \
g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
__FILE__, G_STRINGIFY (__LINE__), \
__VA_ARGS__)
#endif
#elif defined(G_HAVE_GNUC_VARARGS) && !G_ANALYZER_ANALYZING
-#ifdef G_LOG_USE_STRUCTURED
+#if defined(G_LOG_USE_STRUCTURED) && GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_56
#define g_error(format...) G_STMT_START { \
g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
__FILE__, G_STRINGIFY (__LINE__), \
dt = g_date_time_new_from_iso8601 ("not a date", NULL);
g_assert_null (dt);
+ dt = g_date_time_new_from_iso8601 (" +55", NULL);
+ g_assert_null (dt);
+
/* Check common case */
dt = g_date_time_new_from_iso8601 ("2016-08-24T22:10:42Z", NULL);
ASSERT_DATE (dt, 2016, 8, 24);
project('glib', 'c', 'cpp',
- version : '2.60.6',
+ version : '2.60.7',
meson_version : '>= 0.48.0',
default_options : [
'buildtype=debugoptimized',