import glib2-2.56.4-161.el8

c8 imports/c8/glib2-2.56.4-161.el8
CentOS Sources 2 years ago committed by MSVSphere Packaging Team
commit dc0c45dba4

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/glib-2.56.4.tar.xz

@ -0,0 +1 @@
4064eb1eb5ff626c211e86bc939f8b743ceafaba SOURCES/glib-2.56.4.tar.xz

@ -0,0 +1,658 @@
From 5634fd61f17d28dfc05cd47cfbd2bd2f21e6d2b1 Mon Sep 17 00:00:00 2001
From: Allison Lortie <desrt@desrt.ca>
Date: Wed, 2 Aug 2017 11:06:03 +0100
Subject: [PATCH 1/4] gsettings: cleanup default value lookup
There are a couple of different ways (and soon one more) to access the
default value of a key. Clean up the various places that access this to
avoid duplication.
https://bugzilla.gnome.org/show_bug.cgi?id=746592
---
gio/gsettings.c | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 10d394d69..5e5816d57 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1204,10 +1204,7 @@ g_settings_get_value (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
g_settings_schema_key_clear (&skey);
@@ -1304,10 +1301,7 @@ g_settings_get_default_value (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, TRUE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
g_settings_schema_key_clear (&skey);
@@ -1360,10 +1354,7 @@ g_settings_get_enum (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
result = g_settings_schema_key_to_enum (&skey, value);
g_settings_schema_key_clear (&skey);
@@ -1473,10 +1464,7 @@ g_settings_get_flags (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
result = g_settings_schema_key_to_flags (&skey, value);
g_settings_schema_key_clear (&skey);
--
2.21.0
From 89c6e8f4a0bcda4b58dbaea713e62be01cfc2087 Mon Sep 17 00:00:00 2001
From: Allison Lortie <desrt@desrt.ca>
Date: Wed, 2 Aug 2017 11:08:17 +0100
Subject: [PATCH 2/4] gsettingsschema: Allow per-desktop overrides
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Recognise a new 'd' option in schema keys which gives a dictionary of
per-desktop default values. This dictionary is searched for the items
found in XDG_CURRENT_DESKTOP, in the order. If nothing matches (or if
the option is missing) then the default value is used as before.
This feature was requested by Alberts Muktupāvels and this patch is
based on an approach devised by them.
https://bugzilla.gnome.org/show_bug.cgi?id=746592
---
gio/gsettings.c | 21 +++++++++++++++++
gio/gsettingsschema-internal.h | 2 ++
gio/gsettingsschema.c | 41 ++++++++++++++++++++++++++++++++++
3 files changed, 64 insertions(+)
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 5e5816d57..f1130c095 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1739,6 +1739,13 @@ g_settings_get_mapped (GSettings *settings,
if (okay) goto okay;
}
+ if ((value = g_settings_schema_key_get_per_desktop_default (&skey)))
+ {
+ okay = mapping (value, &result, user_data);
+ g_variant_unref (value);
+ if (okay) goto okay;
+ }
+
if (mapping (skey.default_value, &result, user_data))
goto okay;
@@ -2647,6 +2654,20 @@ g_settings_binding_key_changed (GSettings *settings,
}
}
+ if (variant == NULL)
+ {
+ variant = g_settings_schema_key_get_per_desktop_default (&binding->key);
+ if (variant &&
+ !binding->get_mapping (&value, variant, binding->user_data))
+ {
+ g_error ("Per-desktop default value for key '%s' in schema '%s' "
+ "was rejected by the binding mapping function.",
+ binding->key.name, g_settings_schema_get_id (binding->key.schema));
+ g_variant_unref (variant);
+ variant = NULL;
+ }
+ }
+
if (variant == NULL)
{
variant = g_variant_ref (binding->key.default_value);
diff --git a/gio/gsettingsschema-internal.h b/gio/gsettingsschema-internal.h
index f54de3b34..5f996b4bc 100644
--- a/gio/gsettingsschema-internal.h
+++ b/gio/gsettingsschema-internal.h
@@ -37,6 +37,7 @@ struct _GSettingsSchemaKey
const GVariantType *type;
GVariant *minimum, *maximum;
GVariant *default_value;
+ GVariant *desktop_overrides;
gint ref_count;
};
@@ -58,6 +59,7 @@ gboolean g_settings_schema_key_type_check (GSettin
GVariant * g_settings_schema_key_range_fixup (GSettingsSchemaKey *key,
GVariant *value);
GVariant * g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key);
+GVariant * g_settings_schema_key_get_per_desktop_default (GSettingsSchemaKey *key);
gint g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
GVariant *value);
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index f1274a369..17b7e3b01 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -27,6 +27,7 @@
#include <glibintl.h>
#include <locale.h>
#include <string.h>
+#include <stdlib.h>
/**
* SECTION:gsettingsschema
@@ -1283,6 +1284,11 @@ g_settings_schema_key_init (GSettingsSchemaKey *key,
endian_fixup (&key->maximum);
break;
+ case 'd':
+ g_variant_get (data, "@a{sv}", &key->desktop_overrides);
+ endian_fixup (&key->desktop_overrides);
+ break;
+
default:
g_warning ("unknown schema extension '%c'", code);
break;
@@ -1303,6 +1309,9 @@ g_settings_schema_key_clear (GSettingsSchemaKey *key)
if (key->maximum)
g_variant_unref (key->maximum);
+ if (key->desktop_overrides)
+ g_variant_unref (key->desktop_overrides);
+
g_variant_unref (key->default_value);
g_settings_schema_unref (key->schema);
@@ -1410,6 +1419,35 @@ g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key)
return value;
}
+GVariant *
+g_settings_schema_key_get_per_desktop_default (GSettingsSchemaKey *key)
+{
+ static const gchar * const *current_desktops;
+ GVariant *value = NULL;
+ gint i;
+
+ if (!key->desktop_overrides)
+ return NULL;
+
+ if (g_once_init_enter (&current_desktops))
+ {
+ const gchar *xdg_current_desktop = g_getenv ("XDG_CURRENT_DESKTOP");
+ gchar **tmp;
+
+ if (xdg_current_desktop != NULL && xdg_current_desktop[0] != '\0')
+ tmp = g_strsplit (xdg_current_desktop, G_SEARCHPATH_SEPARATOR_S, -1);
+ else
+ tmp = g_new0 (gchar *, 0 + 1);
+
+ g_once_init_leave (&current_desktops, (const gchar **) tmp);
+ }
+
+ for (i = 0; value == NULL && current_desktops[i] != NULL; i++)
+ value = g_variant_lookup_value (key->desktop_overrides, current_desktops[i], NULL);
+
+ return value;
+}
+
gint
g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
GVariant *value)
@@ -1698,6 +1736,9 @@ g_settings_schema_key_get_default_value (GSettingsSchemaKey *key)
value = g_settings_schema_key_get_translated_default (key);
+ if (!value)
+ value = g_settings_schema_key_get_per_desktop_default (key);
+
if (!value)
value = g_variant_ref (key->default_value);
--
2.21.0
From 3710e830de015829c086c69181a8703645d577ec Mon Sep 17 00:00:00 2001
From: Allison Lortie <desrt@desrt.ca>
Date: Wed, 2 Aug 2017 11:10:18 +0100
Subject: [PATCH 3/4] glib-compile-schemas: Handle per-desktop overrides
Add a new syntax to override files: if the group name has a ':' in it,
it indicates that we want to override the default values of keys for
only one desktop. For example:
[org.gnome.desktop.interface:Unity]
font-name='Ubuntu 12'
Will override the settings, only if "Unity" is found in
XDG_CURRENT_DESKTOP. Multiple per-desktop overrides can be specified
for a given key: the one which comes first in XDG_CURRENT_DESKTOP will
be used.
https://bugzilla.gnome.org/show_bug.cgi?id=746592
---
gio/glib-compile-schemas.c | 83 ++++++++++++++++++++++++++++++++++----
1 file changed, 75 insertions(+), 8 deletions(-)
diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c
index 2dc8c7171..59fb68ee7 100644
--- a/gio/glib-compile-schemas.c
+++ b/gio/glib-compile-schemas.c
@@ -179,6 +179,8 @@ typedef struct
GString *unparsed_default_value;
GVariant *default_value;
+ GVariantDict *desktop_overrides;
+
GString *strinfo;
gboolean is_enum;
gboolean is_flags;
@@ -731,6 +733,11 @@ key_state_serialise (KeyState *state)
g_variant_builder_add (&builder, "(y(**))", 'r',
state->minimum, state->maximum);
+ /* per-desktop overrides */
+ if (state->desktop_overrides)
+ g_variant_builder_add (&builder, "(y@a{sv})", 'd',
+ g_variant_dict_end (state->desktop_overrides));
+
state->serialised = g_variant_builder_end (&builder);
}
@@ -768,6 +775,9 @@ key_state_free (gpointer data)
if (state->serialised)
g_variant_unref (state->serialised);
+ if (state->desktop_overrides)
+ g_variant_dict_unref (state->desktop_overrides);
+
g_slice_free (KeyState, state);
}
@@ -1878,6 +1888,8 @@ set_overrides (GHashTable *schema_table,
gchar **groups;
gint i;
+ g_debug ("Processing override file '%s'", filename);
+
key_file = g_key_file_new ();
if (!g_key_file_load_from_file (key_file, filename, 0, &error))
{
@@ -1900,18 +1912,31 @@ set_overrides (GHashTable *schema_table,
for (i = 0; groups[i]; i++)
{
const gchar *group = groups[i];
+ const gchar *schema_name;
+ const gchar *desktop_id;
SchemaState *schema;
+ gchar **pieces;
gchar **keys;
gint j;
- schema = g_hash_table_lookup (schema_table, group);
+ pieces = g_strsplit (group, ":", 2);
+ schema_name = pieces[0];
+ desktop_id = pieces[1];
+
+ g_debug ("Processing group '%s' (schema '%s', %s)",
+ group, schema_name, desktop_id ? desktop_id : "all desktops");
+
+ schema = g_hash_table_lookup (schema_table, schema_name);
if (schema == NULL)
- /* Having the schema not be installed is expected to be a
- * common case. Don't even emit an error message about
- * that.
- */
- continue;
+ {
+ /* Having the schema not be installed is expected to be a
+ * common case. Don't even emit an error message about
+ * that.
+ */
+ g_strfreev (pieces);
+ continue;
+ }
keys = g_key_file_get_keys (key_file, group, NULL, NULL);
g_assert (keys != NULL);
@@ -1939,6 +1964,32 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _(" and --strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
+ g_strfreev (groups);
+ g_strfreev (keys);
+
+ return FALSE;
+ }
+
+ if (desktop_id != NULL && state->l10n)
+ {
+ /* Let's avoid the n*m case of per-desktop localised
+ * default values, and just forbid it.
+ */
+ fprintf (stderr,
+ _("cannot provide per-desktop overrides for localised "
+ "key '%s' in schema '%s' (override file '%s')"),
+ key, group, filename);
+
+ if (!strict)
+ {
+ fprintf (stderr, _("; ignoring override for this key.\n"));
+ continue;
+ }
+
+ fprintf (stderr, _(" and --strict was specified; exiting.\n"));
+ g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -1969,6 +2020,7 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _("--strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -1997,6 +2049,7 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _(" and --strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -2025,6 +2078,7 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _(" and --strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -2032,11 +2086,24 @@ set_overrides (GHashTable *schema_table,
}
}
- g_variant_unref (state->default_value);
- state->default_value = value;
+ if (desktop_id != NULL)
+ {
+ if (state->desktop_overrides == NULL)
+ state->desktop_overrides = g_variant_dict_new (NULL);
+
+ g_variant_dict_insert_value (state->desktop_overrides, desktop_id, value);
+ g_variant_unref (value);
+ }
+ else
+ {
+ g_variant_unref (state->default_value);
+ state->default_value = value;
+ }
+
g_free (string);
}
+ g_strfreev (pieces);
g_strfreev (keys);
}
--
2.21.0
From 2ca9218fb46f32fa02bed43c6e60243c8c5d656f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alberts=20Muktup=C4=81vels?= <alberts.muktupavels@gmail.com>
Date: Tue, 19 Jun 2018 23:39:24 +0300
Subject: [PATCH 4/4] Add a test for per-desktop overrides
---
gio/glib-compile-schemas.c | 1 +
gio/tests/Makefile.am | 2 +
gio/tests/gsettings.c | 106 ++++++++++++++++++-
gio/tests/org.gtk.test.gschema.override.orig | 2 +
gio/tests/org.gtk.test.gschema.xml.orig | 6 ++
5 files changed, 116 insertions(+), 1 deletion(-)
create mode 100644 gio/tests/org.gtk.test.gschema.override.orig
diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c
index 59fb68ee7..00dd64146 100644
--- a/gio/glib-compile-schemas.c
+++ b/gio/glib-compile-schemas.c
@@ -2139,6 +2139,7 @@ main (int argc, char **argv)
/* These options are only for use in the gschema-compile tests */
{ "schema-file", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME_ARRAY, &schema_files, NULL, NULL },
+ { "override-file", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME_ARRAY, &override_files, NULL, NULL },
{ NULL }
};
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 49a19bf4a..b41317ad9 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -367,12 +367,14 @@ test.mo: de.po
EXTRA_DIST += de.po
dist_uninstalled_test_data += \
org.gtk.test.gschema.xml.orig \
+ org.gtk.test.gschema.override.orig \
org.gtk.schemasourcecheck.gschema.xml \
testenum.h \
enums.xml.template
# Generated while running the testcase itself...
CLEANFILES += \
org.gtk.test.gschema.xml \
+ org.gtk.test.gschema.override \
org.gtk.test.enums.xml \
gsettings.store \
gschemas.compiled \
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
index 2be4122fe..acdeead4c 100644
--- a/gio/tests/gsettings.c
+++ b/gio/tests/gsettings.c
@@ -2192,6 +2192,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
"org.gtk.test.range.direct",
"org.gtk.test.mapped",
"org.gtk.test.descriptions",
+ "org.gtk.test.per-desktop",
NULL));
}
@@ -2583,6 +2584,100 @@ test_default_value (void)
g_object_unref (settings);
}
+static gboolean
+string_map_func (GVariant *value,
+ gpointer *result,
+ gpointer user_data)
+{
+ const gchar *str;
+
+ str = g_variant_get_string (value, NULL);
+ *result = g_variant_new_string (str);
+
+ return TRUE;
+}
+
+/* Test that per-desktop values from org.gtk.test.gschema.override
+ * does not change default value if current desktop is not listed in
+ * $XDG_CURRENT_DESKTOP.
+ */
+static void
+test_per_desktop (void)
+{
+ GSettings *settings;
+ TestObject *obj;
+ gpointer p;
+ gchar *str;
+
+ settings = g_settings_new ("org.gtk.test.per-desktop");
+ obj = test_object_new ();
+
+ if (!g_test_subprocess ())
+ {
+ g_test_trap_subprocess ("/gsettings/per-desktop/subprocess", 0, 0);
+ g_test_trap_assert_passed ();
+ }
+
+ str = g_settings_get_string (settings, "desktop");
+ g_assert_cmpstr (str, ==, "GNOME");
+ g_free (str);
+
+ p = g_settings_get_mapped (settings, "desktop", string_map_func, NULL);
+
+ str = g_variant_dup_string (p, NULL);
+ g_assert_cmpstr (str, ==, "GNOME");
+ g_free (str);
+
+ g_variant_unref (p);
+
+ g_settings_bind (settings, "desktop", obj, "string", G_SETTINGS_BIND_DEFAULT);
+
+ g_object_get (obj, "string", &str, NULL);
+ g_assert_cmpstr (str, ==, "GNOME");
+ g_free (str);
+
+ g_object_unref (settings);
+ g_object_unref (obj);
+}
+
+/* Test that per-desktop values from org.gtk.test.gschema.override
+ * are successfully loaded based on the value of $XDG_CURRENT_DESKTOP.
+ */
+static void
+test_per_desktop_subprocess (void)
+{
+ GSettings *settings;
+ TestObject *obj;
+ gpointer p;
+ gchar *str;
+
+ g_setenv ("XDG_CURRENT_DESKTOP", "GNOME-Classic:GNOME", TRUE);
+
+ settings = g_settings_new ("org.gtk.test.per-desktop");
+ obj = test_object_new ();
+
+ str = g_settings_get_string (settings, "desktop");
+ g_assert_cmpstr (str, ==, "GNOME Classic");
+ g_free (str);
+
+ p = g_settings_get_mapped (settings, "desktop", string_map_func, NULL);
+
+ str = g_variant_dup_string (p, NULL);
+ g_assert_cmpstr (str, ==, "GNOME Classic");
+ g_free (str);
+
+ g_variant_unref (p);
+
+ g_settings_bind (settings, "desktop", obj, "string", G_SETTINGS_BIND_DEFAULT);
+
+ g_object_get (obj, "string", &str, NULL);
+ g_assert_cmpstr (str, ==, "GNOME Classic");
+ g_free (str);
+
+ g_object_unref (settings);
+ g_object_unref (obj);
+}
+
static void
test_extended_schema (void)
{
@@ -2603,6 +2698,7 @@ int
main (int argc, char *argv[])
{
gchar *schema_text;
+ gchar *override_text;
gchar *enums;
gint result;
@@ -2625,6 +2721,7 @@ main (int argc, char *argv[])
g_setenv ("XDG_DATA_DIRS", ".", TRUE);
g_setenv ("XDG_DATA_HOME", ".", TRUE);
g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
+ g_setenv ("XDG_CURRENT_DESKTOP", "", TRUE);
if (!backend_set)
g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
@@ -2647,6 +2744,10 @@ main (int argc, char *argv[])
g_assert (g_file_set_contents ("org.gtk.test.gschema.xml", schema_text, -1, NULL));
g_free (schema_text);
+ g_assert (g_file_get_contents (SRCDIR "/org.gtk.test.gschema.override.orig", &override_text, NULL, NULL));
+ g_assert (g_file_set_contents ("org.gtk.test.gschema.override", override_text, -1, NULL));
+ g_free (override_text);
+
/* Meson build defines this, autotools build does not */
#ifndef GLIB_COMPILE_SCHEMAS
#define GLIB_COMPILE_SCHEMAS "../glib-compile-schemas"
@@ -2655,7 +2756,8 @@ main (int argc, char *argv[])
g_remove ("gschemas.compiled");
g_assert (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=. "
"--schema-file=org.gtk.test.enums.xml "
- "--schema-file=org.gtk.test.gschema.xml",
+ "--schema-file=org.gtk.test.gschema.xml "
+ "--override-file=org.gtk.test.gschema.override",
NULL, NULL, &result, NULL));
g_assert (result == 0);
@@ -2736,6 +2838,8 @@ main (int argc, char *argv[])
g_test_add_func ("/gsettings/read-descriptions", test_read_descriptions);
g_test_add_func ("/gsettings/test-extended-schema", test_extended_schema);
g_test_add_func ("/gsettings/default-value", test_default_value);
+ g_test_add_func ("/gsettings/per-desktop", test_per_desktop);
+ g_test_add_func ("/gsettings/per-desktop/subprocess", test_per_desktop_subprocess);
result = g_test_run ();
diff --git a/gio/tests/org.gtk.test.gschema.override.orig b/gio/tests/org.gtk.test.gschema.override.orig
new file mode 100644
index 000000000..6694baace
--- /dev/null
+++ b/gio/tests/org.gtk.test.gschema.override.orig
@@ -0,0 +1,2 @@
+[org.gtk.test.per-desktop:GNOME-Classic]
+desktop = "GNOME Classic"
diff --git a/gio/tests/org.gtk.test.gschema.xml.orig b/gio/tests/org.gtk.test.gschema.xml.orig
index c07558335..fbcdce683 100644
--- a/gio/tests/org.gtk.test.gschema.xml.orig
+++ b/gio/tests/org.gtk.test.gschema.xml.orig
@@ -209,4 +209,10 @@
</key>
</schema>
+ <schema id="org.gtk.test.per-desktop" path="/tests/per-desktop/">
+ <key name="desktop" type="s">
+ <default>"GNOME"</default>
+ </key>
+ </schema>
+
</schemalist>
--
2.21.0

@ -0,0 +1,139 @@
From 08f5ab3c3a1877e4a8965a9075bd7675f64eae53 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 27 Sep 2019 14:46:18 +0100
Subject: [PATCH 1/2] gfile: Factor out flags when copying files
This introduces no functional changes; just reduces duplication in the
code a little.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
---
gio/gfile.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index 29ebaaa62..a617b4cc8 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3184,6 +3184,7 @@ file_copy_fallback (GFile *source,
const char *target;
char *attrs_to_read;
gboolean do_set_attributes = FALSE;
+ GFileCreateFlags create_flags;
/* need to know the file type */
info = g_file_query_info (source,
@@ -3274,18 +3275,21 @@ file_copy_fallback (GFile *source,
* If a future API like g_file_replace_with_info() is added, switch
* this code to use that.
*/
+ create_flags = G_FILE_CREATE_PRIVATE;
+ if (flags & G_FILE_COPY_OVERWRITE)
+ create_flags |= G_FILE_CREATE_REPLACE_DESTINATION;
+
if (G_IS_LOCAL_FILE (destination))
{
if (flags & G_FILE_COPY_OVERWRITE)
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION |
- G_FILE_CREATE_PRIVATE, info,
+ create_flags, info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, G_FILE_CREATE_PRIVATE, info,
+ FALSE, create_flags, info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
@@ -3293,13 +3297,12 @@ file_copy_fallback (GFile *source,
out = (GOutputStream *)g_file_replace (destination,
NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION |
- G_FILE_CREATE_PRIVATE,
+ create_flags,
cancellable, error);
}
else
{
- out = (GOutputStream *)g_file_create (destination, G_FILE_CREATE_PRIVATE, cancellable, error);
+ out = (GOutputStream *)g_file_create (destination, create_flags, cancellable, error);
}
if (!out)
--
2.37.3
From b37d628c01da0bd61348b3ac73b7a436af008d8d Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 27 Sep 2019 15:02:32 +0100
Subject: [PATCH 2/2] =?UTF-8?q?gfile:=20Don=E2=80=99t=20copy=20files=20as?=
=?UTF-8?q?=20private=20if=20using=20default=20permissions?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If a copy operation is started with `G_FILE_COPY_TARGET_DEFAULT_PERMS`,
dont create the destination file as private. Instead, create it with
the process current umask (i.e. default permissions).
This is a partial re-work of commit d8f8f4d637ce43f8699ba94c9b, with
input from Ondrej Holy.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #174
---
gio/gfile.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index a617b4cc8..447da3cfb 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3274,8 +3274,22 @@ file_copy_fallback (GFile *source,
*
* If a future API like g_file_replace_with_info() is added, switch
* this code to use that.
+ *
+ * Use %G_FILE_CREATE_PRIVATE unless
+ * - we were told to create the file with default permissions (i.e. the
+ * process umask),
+ * - or if the source file is on a file system which doesnt support
+ * `unix::mode` (in which case it probably also makes sense to create the
+ * destination with default permissions because the source cannot be
+ * private),
+ * - or if the destination file is a `GLocalFile`, in which case we can
+ * directly open() it with the permissions from the source file.
*/
- create_flags = G_FILE_CREATE_PRIVATE;
+ create_flags = G_FILE_CREATE_NONE;
+ if (!(flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) &&
+ g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE) &&
+ !G_IS_LOCAL_FILE (destination))
+ create_flags |= G_FILE_CREATE_PRIVATE;
if (flags & G_FILE_COPY_OVERWRITE)
create_flags |= G_FILE_CREATE_REPLACE_DESTINATION;
@@ -3285,11 +3299,13 @@ file_copy_fallback (GFile *source,
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- create_flags, info,
+ create_flags,
+ (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) ? NULL : info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, create_flags, info,
+ FALSE, create_flags,
+ (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) ? NULL : info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
--
2.37.3

@ -0,0 +1,371 @@
From ef1035d9d86464ea0b5dde60a7a0e190895fdf5b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Mon, 14 Oct 2019 08:22:24 +0100
Subject: [PATCH] gcredentialsprivate: Document the various private macros
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gcredentialsprivate.h | 59 +++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h
index 4d1c420a8..06f0aed19 100644
--- a/gio/gcredentialsprivate.h
+++ b/gio/gcredentialsprivate.h
@@ -22,6 +22,65 @@
#include "gio/gcredentials.h"
#include "gio/gnetworking.h"
+/*
+ * G_CREDENTIALS_SUPPORTED:
+ *
+ * Defined to 1 if GCredentials works.
+ */
+#undef G_CREDENTIALS_SUPPORTED
+
+/*
+ * G_CREDENTIALS_USE_LINUX_UCRED, etc.:
+ *
+ * Defined to 1 if GCredentials uses Linux `struct ucred`, etc.
+ */
+#undef G_CREDENTIALS_USE_LINUX_UCRED
+#undef G_CREDENTIALS_USE_FREEBSD_CMSGCRED
+#undef G_CREDENTIALS_USE_NETBSD_UNPCBID
+#undef G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
+#undef G_CREDENTIALS_USE_SOLARIS_UCRED
+
+/*
+ * G_CREDENTIALS_NATIVE_TYPE:
+ *
+ * Defined to one of G_CREDENTIALS_TYPE_LINUX_UCRED, etc.
+ */
+#undef G_CREDENTIALS_NATIVE_TYPE
+
+/*
+ * G_CREDENTIALS_NATIVE_SIZE:
+ *
+ * Defined to the size of the %G_CREDENTIALS_NATIVE_TYPE
+ */
+#undef G_CREDENTIALS_NATIVE_SIZE
+
+/*
+ * G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED:
+ *
+ * Defined to 1 if we have a message-passing API in which credentials
+ * are attached to a particular message, such as `SCM_CREDENTIALS` on Linux
+ * or `SCM_CREDS` on FreeBSD.
+ */
+#undef G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED
+
+/*
+ * G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED:
+ *
+ * Defined to 1 if we have a `getsockopt()`-style API in which one end of
+ * a socket connection can directly query the credentials of the process
+ * that initiated the other end, such as `getsockopt SO_PEERCRED` on Linux
+ * or `getpeereid()` on multiple operating systems.
+ */
+#undef G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED
+
+/*
+ * G_CREDENTIALS_SPOOFING_SUPPORTED:
+ *
+ * Defined to 1 if privileged processes can spoof their credentials when
+ * using the message-passing API.
+ */
+#undef G_CREDENTIALS_SPOOFING_SUPPORTED
+
#ifdef __linux__
#define G_CREDENTIALS_SUPPORTED 1
#define G_CREDENTIALS_USE_LINUX_UCRED 1
--
2.23.0
From ee502dbbe89a5976c32eb8863c9a9d274ddb60e1 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Mon, 14 Oct 2019 08:47:39 +0100
Subject: [PATCH] GDBus: prefer getsockopt()-style credentials-passing APIs
Conceptually, a D-Bus server is really trying to determine the credentials
of (the process that initiated) a connection, not the credentials that
the process had when it sent a particular message. Ideally, it does
this with a getsockopt()-style API that queries the credentials of the
connection's initiator without requiring any particular cooperation from
that process, avoiding a class of possible failures.
The leading '\0' in the D-Bus protocol is primarily a workaround
for platforms where the message-based credentials-passing API is
strictly better than the getsockopt()-style API (for example, on
FreeBSD, SCM_CREDS includes a process ID but getpeereid() does not),
or where the getsockopt()-style API does not exist at all. As a result
libdbus, the reference implementation of D-Bus, does not implement
Linux SCM_CREDENTIALS at all - it has no reason to do so, because the
SO_PEERCRED socket option is equally informative.
This change makes GDBusServer on Linux more closely match the behaviour
of libdbus.
In particular, GNOME/glib#1831 indicates that when a libdbus client
connects to a GDBus server, recvmsg() sometimes yields a SCM_CREDENTIALS
message with cmsg_data={pid=0, uid=65534, gid=65534}. I think this is
most likely a race condition in the early steps to connect:
client server
connect
accept
send '\0' <- race -> set SO_PASSCRED = 1
receive '\0'
If the server wins the race:
client server
connect
accept
set SO_PASSCRED = 1
send '\0'
receive '\0'
then everything is fine. However, if the client wins the race:
client server
connect
accept
send '\0'
set SO_PASSCRED = 1
receive '\0'
then the kernel does not record credentials for the message containing
'\0' (because SO_PASSCRED was 0 at the time). However, by the time the
server receives the message, the kernel knows that credentials are
desired. I would have expected the kernel to omit the credentials header
in this case, but it seems that instead, it synthesizes a credentials
structure with a dummy process ID 0, a dummy uid derived from
/proc/sys/kernel/overflowuid and a dummy gid derived from
/proc/sys/kernel/overflowgid.
In an unconfigured GDBusServer, hitting this race condition results in
falling back to DBUS_COOKIE_SHA1 authentication, which in practice usually
succeeds in authenticating the peer's uid. However, we encourage AF_UNIX
servers on Unix platforms to allow only EXTERNAL authentication as a
security-hardening measure, because DBUS_COOKIE_SHA1 relies on a series
of assumptions including a cryptographically strong PRNG and a shared
home directory with no write access by others, which are not necessarily
true for all operating systems and users. EXTERNAL authentication will
fail if the server cannot determine the client's credentials.
In particular, this caused a regression when CVE-2019-14822 was fixed
in ibus, which appears to be resolved by this commit. Qt clients
(which use libdbus) intermittently fail to connect to an ibus server
(which uses GDBusServer), because ibus no longer allows DBUS_COOKIE_SHA1
authentication or non-matching uids.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Closes: https://gitlab.gnome.org/GNOME/glib/issues/1831
---
gio/gcredentialsprivate.h | 18 ++++++++++++++++++
gio/gdbusauth.c | 27 +++++++++++++++++++++++++--
2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h
index 06f0aed19..e9ec09b9f 100644
--- a/gio/gcredentialsprivate.h
+++ b/gio/gcredentialsprivate.h
@@ -81,6 +81,18 @@
*/
#undef G_CREDENTIALS_SPOOFING_SUPPORTED
+/*
+ * G_CREDENTIALS_PREFER_MESSAGE_PASSING:
+ *
+ * Defined to 1 if the data structure transferred by the message-passing
+ * API is strictly more informative than the one transferred by the
+ * `getsockopt()`-style API, and hence should be preferred, even for
+ * protocols like D-Bus that are defined in terms of the credentials of
+ * the (process that opened the) socket, as opposed to the credentials
+ * of an individual message.
+ */
+#undef G_CREDENTIALS_PREFER_MESSAGE_PASSING
+
#ifdef __linux__
#define G_CREDENTIALS_SUPPORTED 1
#define G_CREDENTIALS_USE_LINUX_UCRED 1
@@ -100,6 +112,12 @@
#define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct cmsgcred))
#define G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1
#define G_CREDENTIALS_SPOOFING_SUPPORTED 1
+/* GLib doesn't implement it yet, but FreeBSD's getsockopt()-style API
+ * is getpeereid(), which is not as informative as struct cmsgcred -
+ * it does not tell us the PID. As a result, libdbus prefers to use
+ * SCM_CREDS, and if we implement getpeereid() in future, we should
+ * do the same. */
+#define G_CREDENTIALS_PREFER_MESSAGE_PASSING 1
#elif defined(__NetBSD__)
#define G_CREDENTIALS_SUPPORTED 1
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
index 752ec23fc..14cc5d70e 100644
--- a/gio/gdbusauth.c
+++ b/gio/gdbusauth.c
@@ -31,6 +31,7 @@
#include "gdbusutils.h"
#include "gioenumtypes.h"
#include "gcredentials.h"
+#include "gcredentialsprivate.h"
#include "gdbusprivate.h"
#include "giostream.h"
#include "gdatainputstream.h"
@@ -969,9 +970,31 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
- /* first read the NUL-byte */
+ /* read the NUL-byte, possibly with credentials attached */
#ifdef G_OS_UNIX
- if (G_IS_UNIX_CONNECTION (auth->priv->stream))
+#ifndef G_CREDENTIALS_PREFER_MESSAGE_PASSING
+ if (G_IS_SOCKET_CONNECTION (auth->priv->stream))
+ {
+ GSocket *sock = g_socket_connection_get_socket (G_SOCKET_CONNECTION (auth->priv->stream));
+
+ local_error = NULL;
+ credentials = g_socket_get_credentials (sock, &local_error);
+
+ if (credentials == NULL && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
+ {
+ g_propagate_error (error, local_error);
+ goto out;
+ }
+ else
+ {
+ /* Clear the error indicator, so we can retry with
+ * g_unix_connection_receive_credentials() if necessary */
+ g_clear_error (&local_error);
+ }
+ }
+#endif
+
+ if (credentials == NULL && G_IS_UNIX_CONNECTION (auth->priv->stream))
{
local_error = NULL;
credentials = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (auth->priv->stream),
--
2.23.0
From 1485a97d8051b0aa047987f7b0c0bfe4ba4ce55b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Fri, 18 Oct 2019 10:55:09 +0100
Subject: [PATCH] credentials: Invalid Linux struct ucred means "no
information"
On Linux, if getsockopt SO_PEERCRED is used on a TCP socket, one
might expect it to fail with an appropriate error like ENOTSUP or
EPROTONOSUPPORT. However, it appears that in fact it succeeds, but
yields a credentials structure with pid 0, uid -1 and gid -1. These
are not real process, user and group IDs that can be allocated to a
real process (pid 0 needs to be reserved to give kill(0) its documented
special semantics, and similarly uid and gid -1 need to be reserved for
setresuid() and setresgid()) so it is not meaningful to signal them to
high-level API users.
An API user with Linux-specific knowledge can still inspect these fields
via g_credentials_get_native() if desired.
Similarly, if SO_PASSCRED is used to receive a SCM_CREDENTIALS message
on a receiving Unix socket, but the sending socket had not enabled
SO_PASSCRED at the time that the message was sent, it is possible
for it to succeed but yield a credentials structure with pid 0, uid
/proc/sys/kernel/overflowuid and gid /proc/sys/kernel/overflowgid. Even
if we were to read those pseudo-files, we cannot distinguish between
the overflow IDs and a real process that legitimately has the same IDs
(typically they are set to 'nobody' and 'nogroup', which can be used
by a real process), so we detect this situation by noticing that
pid == 0, and to save syscalls we do not read the overflow IDs from
/proc at all.
This results in a small API change: g_credentials_is_same_user() now
returns FALSE if we compare two credentials structures that are both
invalid. This seems like reasonable, conservative behaviour: if we cannot
prove that they are the same user, we should assume they are not.
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gcredentials.c | 42 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/gio/gcredentials.c b/gio/gcredentials.c
index c350e3c88..c4794ded7 100644
--- a/gio/gcredentials.c
+++ b/gio/gcredentials.c
@@ -265,6 +265,35 @@ g_credentials_to_string (GCredentials *credentials)
/* ---------------------------------------------------------------------------------------------------- */
+#if G_CREDENTIALS_USE_LINUX_UCRED
+/*
+ * Check whether @native contains invalid data. If getsockopt SO_PEERCRED
+ * is used on a TCP socket, it succeeds but yields a credentials structure
+ * with pid 0, uid -1 and gid -1. Similarly, if SO_PASSCRED is used on a
+ * receiving Unix socket when the sending socket did not also enable
+ * SO_PASSCRED, it can succeed but yield a credentials structure with
+ * pid 0, uid /proc/sys/kernel/overflowuid and gid
+ * /proc/sys/kernel/overflowgid.
+ */
+static gboolean
+linux_ucred_check_valid (struct ucred *native,
+ GError **error)
+{
+ if (native->pid == 0
+ || native->uid == -1
+ || native->gid == -1)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("GCredentials contains invalid data"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+
/**
* g_credentials_is_same_user:
* @credentials: A #GCredentials.
@@ -294,7 +323,8 @@ g_credentials_is_same_user (GCredentials *credentials,
ret = FALSE;
#if G_CREDENTIALS_USE_LINUX_UCRED
- if (credentials->native.uid == other_credentials->native.uid)
+ if (linux_ucred_check_valid (&credentials->native, NULL)
+ && credentials->native.uid == other_credentials->native.uid)
ret = TRUE;
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
if (credentials->native.cmcred_euid == other_credentials->native.cmcred_euid)
@@ -453,7 +483,10 @@ g_credentials_get_unix_user (GCredentials *credentials,
g_return_val_if_fail (error == NULL || *error == NULL, -1);
#if G_CREDENTIALS_USE_LINUX_UCRED
- ret = credentials->native.uid;
+ if (linux_ucred_check_valid (&credentials->native, error))
+ ret = credentials->native.uid;
+ else
+ ret = -1;
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
ret = credentials->native.cmcred_euid;
#elif G_CREDENTIALS_USE_NETBSD_UNPCBID
@@ -499,7 +532,10 @@ g_credentials_get_unix_pid (GCredentials *credentials,
g_return_val_if_fail (error == NULL || *error == NULL, -1);
#if G_CREDENTIALS_USE_LINUX_UCRED
- ret = credentials->native.pid;
+ if (linux_ucred_check_valid (&credentials->native, error))
+ ret = credentials->native.pid;
+ else
+ ret = -1;
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
ret = credentials->native.cmcred_pid;
#elif G_CREDENTIALS_USE_NETBSD_UNPCBID
--
2.23.0

@ -0,0 +1,654 @@
From fe823e3cfe25c96de5e453d1acbdc036892a9c36 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:07:50 +0100
Subject: [PATCH 1/4] codegen: Support Since and name changing annotations on
annotations
Recursive annotations do seem to be supported, so we should support them
properly in the type system representation. This currently introduces no
behavioural changes, but will be used in upcoming commits.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
gio/gdbus-2.0/codegen/dbustypes.py | 33 ++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
index 359880ff7..29222f987 100644
--- a/gio/gdbus-2.0/codegen/dbustypes.py
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
@@ -27,6 +27,25 @@ class Annotation:
self.key = key
self.value = value
self.annotations = []
+ self.since = ''
+
+ def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container):
+ key = self.key
+ overridden_key = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name')
+ if utils.is_ugly_case(overridden_key):
+ self.key_lower = overridden_key.lower()
+ else:
+ if overridden_key:
+ key = overridden_key
+ self.key_lower = utils.camel_case_to_uscore(key).lower().replace('-', '_').replace('.', '_')
+
+ if len(self.since) == 0:
+ self.since = utils.lookup_since(self.annotations)
+ if len(self.since) == 0:
+ self.since = container.since
+
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Arg:
def __init__(self, name, signature):
@@ -229,6 +248,8 @@ class Arg:
self.gvalue_get = 'g_value_get_boxed'
self.array_annotation = '(array zero-terminated=1)'
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Method:
def __init__(self, name):
@@ -270,6 +291,9 @@ class Method:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Signal:
def __init__(self, name):
self.name = name
@@ -305,6 +329,9 @@ class Signal:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Property:
def __init__(self, name, signature, access):
self.name = name
@@ -357,6 +384,9 @@ class Property:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
# FIXME: for now we only support 'false' and 'const' on the signal itself, see #674913 and
# http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
# for details
@@ -436,3 +466,6 @@ class Interface:
for p in self.properties:
p.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
--
2.35.1
From dcb1c3fbd588dcf5cdcaeb65547fdbe176312e10 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:10:07 +0100
Subject: [PATCH 2/4] codegen: Add --interface-info-[body|header] modes
These generate basic .c and .h files containing the GDBusInterfaceInfo
for a D-Bus introspection XML file, but no other code (no skeletons,
proxies, GObjects, etc.).
This is useful for projects who want to describe their D-Bus interfaces
using introspection XML, but who wish to implement the interfaces
manually (for various reasons, typically because the skeletons generated
by gdbus-codegen are too simplistic and limiting). Previously, these
projects would have had to write the GDBusInterfaceInfo manually, which
is painstaking and error-prone.
The new --interface-info-[body|header] options are very similar to
--[body|header], but mutually exclusive with them.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
docs/reference/gio/gdbus-codegen.xml | 65 +++++-
gio/gdbus-2.0/codegen/codegen.py | 280 ++++++++++++++++++++++++++
gio/gdbus-2.0/codegen/codegen_main.py | 39 ++++
3 files changed, 377 insertions(+), 7 deletions(-)
diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml
index b1145e5ef..3e1a9d668 100644
--- a/docs/reference/gio/gdbus-codegen.xml
+++ b/docs/reference/gio/gdbus-codegen.xml
@@ -39,6 +39,8 @@
<arg><option>--xml-files</option> <replaceable>FILE</replaceable></arg>
<arg><option>--header</option></arg>
<arg><option>--body</option></arg>
+ <arg><option>--interface-info-header</option></arg>
+ <arg><option>--interface-info-body</option></arg>
<arg><option>--output</option> <replaceable>OUTFILE</replaceable></arg>
<group choice="plain" rep="repeat">
<arg>
@@ -69,7 +71,11 @@
arguments on the command line and generates output files.
It currently supports generating C source code (via
<option>--body</option>) or header (via <option>--header</option>)
- and Docbook XML (via <option>--generate-docbook</option>).
+ and Docbook XML (via <option>--generate-docbook</option>). Alternatively,
+ more restricted C source code and headers can be generated, which just
+ contain the interface information (as <type>GDBusInterfaceInfo</type>
+ structures) using <option>--interface-info-body</option> and
+ <option>--interface-info-header</option>.
</para>
</refsect1>
@@ -90,8 +96,11 @@
</para>
<para>
For C code generation either <option>--body</option> that
- generates source code, or <option>--header</option> that
- generates headers, can be used. These options must be used along with
+ generates source code, <option>--header</option> that
+ generates headers, <option>--interface-info-body</option> that generates
+ interface information source code, or
+ <option>--interface-info-header</option> that generates interface information
+ headers, can be used. These options must be used along with
<option>--output</option>, which is used to specify the file to output to.
</para>
<para>
@@ -282,8 +291,10 @@
Directory to output generated source to. Equivalent to changing directory before generation.
</para>
<para>
- This option cannot be used with neither <option>--body</option> nor
- <option>--header</option>, and <option>--output</option> must be used.
+ This option cannot be used with <option>--body</option>,
+ <option>--header</option>, <option>--interface-info-body</option> or
+ <option>--interface-info-header</option>; and
+ <option>--output</option> must be used.
</para>
</listitem>
@@ -321,12 +332,52 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--interface-info-header</option></term>
+ <listitem>
+ <para>
+ If this option is passed, it will generate the header code for the
+ <type>GDBusInterfaceInfo</type> structures only and will write it to
+ the disk by using the path and file name provided by
+ <option>--output</option>.
+ </para>
+ <para>
+ Using <option>--generate-c-code</option>, <option>--generate-docbook</option> or
+ <option>--output-directory</option> are not allowed to be used along with
+ the <option>--interface-info-header</option> and
+ <option>--interface-info-body</option> options, because these options
+ are used to generate only one file.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--interface-info-body</option></term>
+ <listitem>
+ <para>
+ If this option is passed, it will generate the source code for the
+ <type>GDBusInterfaceInfo</type> structures only and will write it to
+ the disk by using the path and file name provided by
+ <option>--output</option>.
+ </para>
+ <para>
+ Using <option>--generate-c-code</option>, <option>--generate-docbook</option> or
+ <option>--output-directory</option> are not allowed to be used along with
+ the <option>--interface-info-header</option> and
+ <option>--interface-info-body</option> options, because these options
+ are used to generate only one file.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--output</option> <replaceable>OUTFILE</replaceable></term>
<listitem>
<para>
- The full path where the header (<option>--header</option>) or the source code
- (<option>--body</option>) will be written, using the path and filename provided by
+ The full path where the header (<option>--header</option>,
+ <option>--interface-info-header</option>) or the source code
+ (<option>--body</option>, <option>--interface-info-body</option>) will
+ be written, using the path and filename provided by
<option>--output</option>. The full path could be something like
<literal>$($OUTFILE).{c,h}</literal>.
</para>
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index 442bd3f5d..4e258332d 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -610,6 +610,286 @@ class HeaderCodeGenerator:
# ----------------------------------------------------------------------------------------------------
+class InterfaceInfoHeaderCodeGenerator:
+ def __init__(self, ifaces, namespace, header_name, use_pragma, outfile):
+ self.ifaces = ifaces
+ self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
+ self.header_guard = header_name.upper().replace('.', '_').replace('-', '_').replace('/', '_').replace(':', '_')
+ self.use_pragma = use_pragma
+ self.outfile = outfile
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_header_preamble(self):
+ self.outfile.write(LICENSE_STR.format(config.VERSION))
+ self.outfile.write('\n')
+
+ if self.use_pragma:
+ self.outfile.write('#pragma once\n')
+ else:
+ self.outfile.write('#ifndef __{!s}__\n'.format(self.header_guard))
+ self.outfile.write('#define __{!s}__\n'.format(self.header_guard))
+
+ self.outfile.write('\n')
+ self.outfile.write('#include <gio/gio.h>\n')
+ self.outfile.write('\n')
+ self.outfile.write('G_BEGIN_DECLS\n')
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def declare_infos(self):
+ for i in self.ifaces:
+ self.outfile.write('extern const GDBusInterfaceInfo %s_interface;\n' % i.name_lower)
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_header_postamble(self):
+ self.outfile.write('\n')
+ self.outfile.write('G_END_DECLS\n')
+
+ if not self.use_pragma:
+ self.outfile.write('\n')
+ self.outfile.write('#endif /* __{!s}__ */\n'.format(self.header_guard))
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate(self):
+ self.generate_header_preamble()
+ self.declare_infos()
+ self.generate_header_postamble()
+
+# ----------------------------------------------------------------------------------------------------
+
+class InterfaceInfoBodyCodeGenerator:
+ def __init__(self, ifaces, namespace, header_name, outfile):
+ self.ifaces = ifaces
+ self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
+ self.header_name = header_name
+ self.outfile = outfile
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_body_preamble(self):
+ self.outfile.write(LICENSE_STR.format(config.VERSION))
+ self.outfile.write('\n')
+ self.outfile.write('#ifdef HAVE_CONFIG_H\n'
+ '# include "config.h"\n'
+ '#endif\n'
+ '\n'
+ '#include "%s"\n'
+ '\n'
+ '#include <string.h>\n'
+ % (self.header_name))
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_array(self, array_name_lower, element_type, elements):
+ self.outfile.write('const %s * const %s[] =\n' % (element_type, array_name_lower))
+ self.outfile.write('{\n')
+ for (_, name) in sorted(elements, key=utils.version_cmp_key):
+ self.outfile.write(' &%s,\n' % name)
+ self.outfile.write(' NULL,\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ def define_annotations(self, array_name_lower, annotations):
+ if len(annotations) == 0:
+ return
+
+ annotation_pointers = []
+
+ for a in annotations:
+ # Skip internal annotations.
+ if a.key.startswith('org.gtk.GDBus'):
+ continue
+
+ self.define_annotations('%s__%s_annotations' % (array_name_lower, a.key_lower), a.annotations)
+
+ self.outfile.write('const GDBusAnnotationInfo %s__%s_annotation =\n' % (array_name_lower, a.key_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % a.key)
+ self.outfile.write(' (gchar *) "%s",\n' % a.value)
+ if len(a.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_annotations,\n' % (array_name_lower, a.key_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (a.since, '%s__%s_annotation' % (array_name_lower, a.key_lower))
+ annotation_pointers.append(key)
+
+ self.generate_array(array_name_lower, 'GDBusAnnotationInfo',
+ annotation_pointers)
+
+ def define_args(self, array_name_lower, args):
+ if len(args) == 0:
+ return
+
+ arg_pointers = []
+
+ for a in args:
+ self.define_annotations('%s__%s_arg_annotations' % (array_name_lower, a.name), a.annotations)
+
+ self.outfile.write('const GDBusArgInfo %s__%s_arg =\n' % (array_name_lower, a.name))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % a.name)
+ self.outfile.write(' (gchar *) "%s",\n' % a.signature)
+ if len(a.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_arg_annotations,\n' % (array_name_lower, a.name))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (a.since, '%s__%s_arg' % (array_name_lower, a.name))
+ arg_pointers.append(key)
+
+ self.generate_array(array_name_lower, 'GDBusArgInfo', arg_pointers)
+
+ def define_infos(self):
+ for i in self.ifaces:
+ self.outfile.write('/* ------------------------------------------------------------------------ */\n')
+ self.outfile.write('/* Definitions for %s */\n' % i.name)
+ self.outfile.write('\n')
+
+ # GDBusMethodInfos.
+ if len(i.methods) > 0:
+ method_pointers = []
+
+ for m in i.methods:
+ self.define_args('%s_interface__%s_method_in_args' % (i.name_lower, m.name_lower), m.in_args)
+ self.define_args('%s_interface__%s_method_out_args' % (i.name_lower, m.name_lower), m.out_args)
+ self.define_annotations('%s_interface__%s_method_annotations' % (i.name_lower, m.name_lower), m.annotations)
+
+ self.outfile.write('const GDBusMethodInfo %s_interface__%s_method =\n' % (i.name_lower, m.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % m.name)
+ if len(m.in_args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_in_args,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no in args */\n')
+ if len(m.out_args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_out_args,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no out args */\n')
+ if len(m.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_method_annotations,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_method' % (i.name_lower, m.name_lower))
+ method_pointers.append(key)
+
+ self.generate_array('%s_interface_methods' % i.name_lower,
+ 'GDBusMethodInfo', method_pointers)
+
+ # GDBusSignalInfos.
+ if len(i.signals) > 0:
+ signal_pointers = []
+
+ for s in i.signals:
+ self.define_args('%s_interface__%s_signal_args' % (i.name_lower, s.name_lower), s.args)
+ self.define_annotations('%s_interface__%s_signal_annotations' % (i.name_lower, s.name_lower), s.annotations)
+
+ self.outfile.write('const GDBusSignalInfo %s_interface__%s_signal =\n' % (i.name_lower, s.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % s.name)
+ if len(s.args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_signal_args,\n' % (i.name_lower, s.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no args */\n')
+ if len(s.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_signal_annotations,\n' % (i.name_lower, s.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_signal' % (i.name_lower, s.name_lower))
+ signal_pointers.append(key)
+
+ self.generate_array('%s_interface_signals' % i.name_lower,
+ 'GDBusSignalInfo', signal_pointers)
+
+ # GDBusPropertyInfos.
+ if len(i.properties) > 0:
+ property_pointers = []
+
+ for p in i.properties:
+ if p.readable and p.writable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+ elif p.readable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
+ elif p.writable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+ else:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
+
+ self.define_annotations('%s_interface__%s_property_annotations' % (i.name_lower, p.name_lower), p.annotations)
+
+ self.outfile.write('const GDBusPropertyInfo %s_interface__%s_property =\n' % (i.name_lower, p.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % p.name)
+ self.outfile.write(' (gchar *) "%s",\n' % p.signature)
+ self.outfile.write(' %s,\n' % flags)
+ if len(p.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_property_annotations,\n' % (i.name_lower, p.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_property' % (i.name_lower, p.name_lower))
+ property_pointers.append(key)
+
+ self.generate_array('%s_interface_properties' % i.name_lower,
+ 'GDBusPropertyInfo', property_pointers)
+
+ # Finally the GDBusInterfaceInfo.
+ self.define_annotations('%s_interface_annotations' % i.name_lower,
+ i.annotations)
+
+ self.outfile.write('const GDBusInterfaceInfo %s_interface =\n' % i.name_lower)
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % i.name)
+ if len(i.methods) > 0:
+ self.outfile.write(' (GDBusMethodInfo **) %s_interface_methods,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no methods */\n')
+ if len(i.signals) > 0:
+ self.outfile.write(' (GDBusSignalInfo **) %s_interface_signals,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no signals */\n')
+ if len(i.properties) > 0:
+ self.outfile.write(' (GDBusPropertyInfo **) %s_interface_properties,\n' % i.name_lower)
+ else:
+ self.outfile.write( 'NULL, /* no properties */\n')
+ if len(i.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface_annotations,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate(self):
+ self.generate_body_preamble()
+ self.define_infos()
+
+# ----------------------------------------------------------------------------------------------------
+
class CodeGenerator:
def __init__(self, ifaces, namespace, generate_objmanager, header_name,
docbook_gen, outfile):
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index 1cfe7c1bb..37efb3bcf 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -175,6 +175,10 @@ def codegen_main():
help='Generate C headers')
group.add_argument('--body', action='store_true',
help='Generate C code')
+ group.add_argument('--interface-info-header', action='store_true',
+ help='Generate GDBusInterfaceInfo C header')
+ group.add_argument('--interface-info-body', action='store_true',
+ help='Generate GDBusInterfaceInfo C code')
group = arg_parser.add_mutually_exclusive_group()
group.add_argument('--output', metavar='FILE',
@@ -210,6 +214,24 @@ def codegen_main():
c_file = args.output
header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
+ elif args.interface_info_header:
+ if args.output is None:
+ print_error('Using --interface-info-header requires --output')
+ if args.c_generate_object_manager:
+ print_error('--c-generate-object-manager is incompatible with '
+ '--interface-info-header')
+
+ h_file = args.output
+ header_name = os.path.basename(h_file)
+ elif args.interface_info_body:
+ if args.output is None:
+ print_error('Using --interface-info-body requires --output')
+ if args.c_generate_object_manager:
+ print_error('--c-generate-object-manager is incompatible with '
+ '--interface-info-body')
+
+ c_file = args.output
+ header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
all_ifaces = []
for fname in args.files + args.xml_files:
@@ -250,6 +272,23 @@ def codegen_main():
outfile)
gen.generate()
+ if args.interface_info_header:
+ with open(h_file, 'w') as outfile:
+ gen = codegen.InterfaceInfoHeaderCodeGenerator(all_ifaces,
+ args.c_namespace,
+ header_name,
+ args.pragma_once,
+ outfile)
+ gen.generate()
+
+ if args.interface_info_body:
+ with open(c_file, 'w') as outfile:
+ gen = codegen.InterfaceInfoBodyCodeGenerator(all_ifaces,
+ args.c_namespace,
+ header_name,
+ outfile)
+ gen.generate()
+
sys.exit(0)
if __name__ == "__main__":
--
2.35.1
From 11de9adfe6f57521ea5ed881b6862480c742414c Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:12:18 +0100
Subject: [PATCH 3/4] codegen: Suppress the old --xml-files option in the
--help output
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Since its deprecated in favour of positional arguments, including it in
the help output is confusing.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
gio/gdbus-2.0/codegen/codegen_main.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index 37efb3bcf..d3763eb0f 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -152,7 +152,7 @@ def codegen_main():
arg_parser.add_argument('files', metavar='FILE', nargs='*',
help='D-Bus introspection XML file')
arg_parser.add_argument('--xml-files', metavar='FILE', action='append', default=[],
- help='D-Bus introspection XML file')
+ help=argparse.SUPPRESS)
arg_parser.add_argument('--interface-prefix', metavar='PREFIX', default='',
help='String to strip from D-Bus interface names for code and docs')
arg_parser.add_argument('--c-namespace', metavar='NAMESPACE', default='',
--
2.35.1
From b2b72837b0545e297db7ded8773377b4b6473a55 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:13:05 +0100
Subject: [PATCH 4/4] codegen: Fix a minor Python linting warning
This introduces no functional changes.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
gio/gdbus-2.0/codegen/codegen_main.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index d3763eb0f..fa9c71373 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -240,7 +240,7 @@ def codegen_main():
parsed_ifaces = parser.parse_dbus_xml(xml_data)
all_ifaces.extend(parsed_ifaces)
- if args.annotate != None:
+ if args.annotate is not None:
apply_annotations(all_ifaces, args.annotate)
for i in all_ifaces:
--
2.35.1

@ -0,0 +1,38 @@
From a18f091c6c090b93cd816f8cd5be763b6e238632 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 7 Feb 2020 17:10:23 +0000
Subject: [PATCH] libcharset: Drop a redundant environment variable
It was used for running tests when we built with autotools, but is no
longer used in the Meson build system. If we need something similar in
future, it should be done by adding internal API to override the
directory on a per-call basis, rather than loading a path from a shared
global table every time.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #1919
---
glib/libcharset/localcharset.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/glib/libcharset/localcharset.c b/glib/libcharset/localcharset.c
index 0c4d544be..ab3a2678d 100644
--- a/glib/libcharset/localcharset.c
+++ b/glib/libcharset/localcharset.c
@@ -117,11 +117,7 @@ _g_locale_get_charset_aliases (void)
const char *base = "charset.alias";
char *file_name;
- /* Make it possible to override the charset.alias location. This is
- necessary for running the testsuite before "make install". */
- dir = getenv ("CHARSETALIASDIR");
- if (dir == NULL || dir[0] == '\0')
- dir = relocate (GLIB_CHARSETALIAS_DIR);
+ dir = relocate (GLIB_CHARSETALIAS_DIR);
/* Concatenate dir and base into freshly allocated file_name. */
{
--
2.31.1

@ -0,0 +1,204 @@
From 4f0a31d66c2a6588495b8ae682f555584dafdf45 Mon Sep 17 00:00:00 2001
From: Claudio Saavedra <csaavedra@igalia.com>
Date: Wed, 21 Oct 2020 13:19:42 +0300
Subject: [PATCH] gmain: g_main_context_check() can skip updating polled FD
sources
If there is a file descriptor source that has a lower priority
than the one for sources that are going to be dispatched,
all subsequent file descriptor sources (internally sorted by
file descriptor identifier) do not get an update in their GPollRec
and later on wrong sources can be dispatched.
Fix this by first finding the first GPollRec that matches the current
GPollFD, instead of relying on it to be the current one. At
the same time, document the assumptions about the ordering of the
file descriptor records and array and make explicit in the documentation
that the array needs to be passed to g_main_context_check() as it was
received from g_main_context_query().
Added a new test that reproduces the bug by creating two file
descriptor sources and an idle one. Since the first
file descriptor created has a lower identifier and a low priority,
the second one is not dispatched even when it has the same, higher,
priority as the idle source. After fixing this bug, both
higher priority sources are dispatched as expected.
While this patch was written independently, a similar fix for this
bug was first submitted by Eugene M in GNOME/glib!562. Having a
second fix that basically does the same is a reassurance that we
are in the right here.
Fixes #1592
---
glib/gmain.c | 32 ++++++++++++++++++++++--
glib/tests/mainloop.c | 57 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 95992253d..a59cd686c 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -3573,7 +3573,10 @@ g_main_context_prepare (GMainContext *context,
* store #GPollFD records that need to be polled.
* @n_fds: (in): length of @fds.
*
- * Determines information necessary to poll this main loop.
+ * Determines information necessary to poll this main loop. You should
+ * be careful to pass the resulting @fds array and its length @n_fds
+ * as is when calling g_main_context_check(), as this function relies
+ * on assumptions made when the array is filled.
*
* You must have successfully acquired the context with
* g_main_context_acquire() before you may call this function.
@@ -3597,6 +3600,10 @@ g_main_context_query (GMainContext *context,
TRACE (GLIB_MAIN_CONTEXT_BEFORE_QUERY (context, max_priority));
+ /* fds is filled sequentially from poll_records. Since poll_records
+ * are incrementally sorted by file descriptor identifier, fds will
+ * also be incrementally sorted.
+ */
n_poll = 0;
lastpollrec = NULL;
for (pollrec = context->poll_records; pollrec; pollrec = pollrec->next)
@@ -3611,6 +3618,10 @@ g_main_context_query (GMainContext *context,
*/
events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL);
+ /* This optimization --using the same GPollFD to poll for more
+ * than one poll record-- relies on the poll records being
+ * incrementally sorted.
+ */
if (lastpollrec && pollrec->fd->fd == lastpollrec->fd->fd)
{
if (n_poll - 1 < n_fds)
@@ -3656,7 +3667,10 @@ g_main_context_query (GMainContext *context,
* the last call to g_main_context_query()
* @n_fds: return value of g_main_context_query()
*
- * Passes the results of polling back to the main loop.
+ * Passes the results of polling back to the main loop. You should be
+ * careful to pass @fds and its length @n_fds as received from
+ * g_main_context_query(), as this functions relies on assumptions
+ * on how @fds is filled.
*
* You must have successfully acquired the context with
* g_main_context_acquire() before you may call this function.
@@ -3711,10 +3725,22 @@ g_main_context_check (GMainContext *context,
return FALSE;
}
+ /* The linear iteration below relies on the assumption that both
+ * poll records and the fds array are incrementally sorted by file
+ * descriptor identifier.
+ */
pollrec = context->poll_records;
i = 0;
while (pollrec && i < n_fds)
{
+ /* Make sure that fds is sorted by file descriptor identifier. */
+ g_assert (i <= 0 || fds[i - 1].fd < fds[i].fd);
+
+ /* Skip until finding the first GPollRec matching the current GPollFD. */
+ while (pollrec && pollrec->fd->fd != fds[i].fd)
+ pollrec = pollrec->next;
+
+ /* Update all consecutive GPollRecs that match. */
while (pollrec && pollrec->fd->fd == fds[i].fd)
{
if (pollrec->priority <= max_priority)
@@ -3725,6 +3751,7 @@ g_main_context_check (GMainContext *context,
pollrec = pollrec->next;
}
+ /* Iterate to next GPollFD. */
i++;
}
@@ -4320,6 +4347,7 @@ g_main_context_add_poll_unlocked (GMainContext *context,
newrec->fd = fd;
newrec->priority = priority;
+ /* Poll records are incrementally sorted by file descriptor identifier. */
prevrec = NULL;
nextrec = context->poll_records;
while (nextrec)
diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c
index f5d672a63..397921f2d 100644
--- a/glib/tests/mainloop.c
+++ b/glib/tests/mainloop.c
@@ -1511,6 +1511,62 @@ test_unix_file_poll (void)
close (fd);
}
+static void
+test_unix_fd_priority (void)
+{
+ gint fd1, fd2;
+ GMainLoop *loop;
+ GSource *source;
+
+ gint s1 = 0;
+ gboolean s2 = FALSE, s3 = FALSE;
+
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1592");
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, count_calls, &s1, NULL);
+ g_source_set_priority (source, 0);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ fd1 = open ("/dev/random", O_RDONLY);
+ g_assert_cmpint (fd1, >=, 0);
+ source = g_unix_fd_source_new (fd1, G_IO_IN);
+ g_source_set_callback (source, (GSourceFunc) (void (*)(void)) (flag_bool), &s2, NULL);
+ g_source_set_priority (source, 10);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ fd2 = open ("/dev/random", O_RDONLY);
+ g_assert_cmpint (fd2, >=, 0);
+ source = g_unix_fd_source_new (fd2, G_IO_IN);
+ g_source_set_callback (source, (GSourceFunc) (void (*)(void)) (flag_bool), &s3, NULL);
+ g_source_set_priority (source, 0);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ /* This tests a bug that depends on the source with the lowest FD
+ identifier to have the lowest priority. Make sure that this is
+ the case. */
+ g_assert_cmpint (fd1, <, fd2);
+
+ g_assert_true (g_main_context_iteration (NULL, FALSE));
+
+ /* Idle source should have been dispatched. */
+ g_assert_cmpint (s1, ==, 1);
+ /* Low priority FD source shouldn't have been dispatched. */
+ g_assert_false (s2);
+ /* Default priority FD source should have been dispatched. */
+ g_assert_true (s3);
+
+ g_main_loop_unref (loop);
+
+ close (fd1);
+ close (fd2);
+}
+
#endif
static gboolean
@@ -1751,6 +1807,7 @@ main (int argc, char *argv[])
g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
g_test_add_func ("/mainloop/wait", test_mainloop_wait);
g_test_add_func ("/mainloop/unix-file-poll", test_unix_file_poll);
+ g_test_add_func ("/mainloop/unix-fd-priority", test_unix_fd_priority);
#endif
g_test_add_func ("/mainloop/nfds", test_nfds);
--
2.31.1

@ -0,0 +1,49 @@
From b6036e23b0477be147211b4e21a6b49cd4d6c9a0 Mon Sep 17 00:00:00 2001
From: Jamie Bainbridge <jamie.bainbridge@gmail.com>
Date: Wed, 8 Sep 2021 12:08:17 +1000
Subject: [PATCH] gutils: Avoid segfault in g_get_user_database_entry
g_get_user_database_entry() uses variable pwd to store the contents of
the call to getpwnam_r(), then capitalises the first letter of pw_name
with g_ascii_toupper (pw->pw_name[0]).
However, as per the getpwnam manpage, the result of that call "may point
to a static area". When this happens, GLib is trying to edit static
memory which belongs to a shared library, so segfaults.
Instead, copy pw_name off to a temporary variable, set uppercase on
that variable, and use the variable to join into the desired string.
Free the new variable after it is no longer needed.
Signed-off-by: Jamie Bainbridge <jamie.bainbridge@gmail.com>
---
glib/gutils.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/glib/gutils.c b/glib/gutils.c
index b7a2113d4..4bccd7229 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -692,14 +692,17 @@ g_get_user_database_entry (void)
{
gchar **gecos_fields;
gchar **name_parts;
+ gchar *uppercase_pw_name;
/* split the gecos field and substitute '&' */
gecos_fields = g_strsplit (pw->pw_gecos, ",", 0);
name_parts = g_strsplit (gecos_fields[0], "&", 0);
- pw->pw_name[0] = g_ascii_toupper (pw->pw_name[0]);
- e.real_name = g_strjoinv (pw->pw_name, name_parts);
+ uppercase_pw_name = g_strdup (pw->pw_name);
+ uppercase_pw_name[0] = g_ascii_toupper (uppercase_pw_name[0]);
+ e.real_name = g_strjoinv (uppercase_pw_name, name_parts);
g_strfreev (gecos_fields);
g_strfreev (name_parts);
+ g_free (uppercase_pw_name);
}
#endif
--
GitLab

@ -0,0 +1,100 @@
From 64b76c7ca5cf5b4ede2f4b423114f46141890e1e Mon Sep 17 00:00:00 2001
From: Robert Ancell <robert.ancell@canonical.com>
Date: Fri, 7 Sep 2018 10:19:05 +1200
Subject: [PATCH] codegen: Change pointer casting to remove type-punning
warnings
The existing code was generating code with undefined results that modern compilers warn about:
accounts-generated.c:204:23: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
(GDBusArgInfo **) &_accounts_accounts_method_info_list_cached_users_OUT_ARG_pointers,
---
gio/gdbus-2.0/codegen/codegen.py | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index e74131cdb..0d95cdcda 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -1129,10 +1129,10 @@ class CodeGenerator:
'\n')
if len(args) > 0:
- self.outfile.write('static const _ExtendedGDBusArgInfo * const %s_pointers[] =\n'
+ self.outfile.write('static const GDBusArgInfo * const %s_pointers[] =\n'
'{\n'%(prefix))
for a in args:
- self.outfile.write(' &%s_%s,\n'%(prefix, a.name))
+ self.outfile.write(' &%s_%s.parent_struct,\n'%(prefix, a.name))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1175,10 +1175,10 @@ class CodeGenerator:
self.outfile.write('};\n'
'\n')
- self.outfile.write('static const _ExtendedGDBusMethodInfo * const _%s_method_info_pointers[] =\n'
+ self.outfile.write('static const GDBusMethodInfo * const _%s_method_info_pointers[] =\n'
'{\n'%(i.name_lower))
for m in i.methods:
- self.outfile.write(' &_%s_method_info_%s,\n'%(i.name_lower, m.name_lower))
+ self.outfile.write(' &_%s_method_info_%s.parent_struct,\n'%(i.name_lower, m.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1209,10 +1209,10 @@ class CodeGenerator:
self.outfile.write('};\n'
'\n')
- self.outfile.write('static const _ExtendedGDBusSignalInfo * const _%s_signal_info_pointers[] =\n'
+ self.outfile.write('static const GDBusSignalInfo * const _%s_signal_info_pointers[] =\n'
'{\n'%(i.name_lower))
for s in i.signals:
- self.outfile.write(' &_%s_signal_info_%s,\n'%(i.name_lower, s.name_lower))
+ self.outfile.write(' &_%s_signal_info_%s.parent_struct,\n'%(i.name_lower, s.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1251,10 +1251,10 @@ class CodeGenerator:
self.outfile.write('};\n'
'\n')
- self.outfile.write('static const _ExtendedGDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
+ self.outfile.write('static const GDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
'{\n'%(i.name_lower))
for p in i.properties:
- self.outfile.write(' &_%s_property_info_%s,\n'%(i.name_lower, p.name_lower))
+ self.outfile.write(' &_%s_property_info_%s.parent_struct,\n'%(i.name_lower, p.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1948,7 +1948,7 @@ class CodeGenerator:
self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
' GVariant *variant;\n'
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
- ' info = _%s_property_info_pointers[prop_id - 1];\n'
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
' variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (object), info->parent_struct.name);\n'
' if (info->use_gvariant)\n'
' {\n'
@@ -2001,7 +2001,7 @@ class CodeGenerator:
self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
' GVariant *variant;\n'
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
- ' info = _%s_property_info_pointers[prop_id - 1];\n'
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
' variant = g_dbus_gvalue_to_gvariant (value, G_VARIANT_TYPE (info->parent_struct.signature));\n'
' g_dbus_proxy_call (G_DBUS_PROXY (object),\n'
' "org.freedesktop.DBus.Properties.Set",\n'
@@ -2887,7 +2887,7 @@ class CodeGenerator:
' if (!_g_value_equal (value, &skeleton->priv->properties[prop_id - 1]))\n'
' {\n'
' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL)\n'
- ' _%s_schedule_emit_changed (skeleton, _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
+ ' _%s_schedule_emit_changed (skeleton, (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
' g_value_copy (value, &skeleton->priv->properties[prop_id - 1]);\n'
' g_object_notify_by_pspec (object, pspec);\n'
' }\n'
--
2.19.1

@ -0,0 +1,56 @@
From d7233ef81e575e84d831414605ba6368394d88b5 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Mon, 15 Oct 2018 21:50:31 +0000
Subject: [PATCH] build-sys: Pass CFLAGS to $(DTRACE)
Fedora is using https://fedoraproject.org/wiki/Changes/Annobin
to try to ensure that all objects are built with hardening flags.
Pass down `CFLAGS` to ensure the SystemTap objects use them.
---
gio/Makefile.am | 2 +-
glib/Makefile.am | 2 +-
gobject/Makefile.am | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fc0b91855..05b20cdef 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -896,7 +896,7 @@ gio_probes.h: gio_probes.d
< $@.tmp > $@ && rm -f $@.tmp
gio_probes.lo: gio_probes.d
- $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC $(DTRACE) -G -s $< -o $@
+ $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -G -s $< -o $@
BUILT_SOURCES += gio_probes.h gio_probes.lo
CLEANFILES += gio_probes.h gio_probes.h.tmp
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 90d33d082..39163aa7f 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -386,7 +386,7 @@ glib_probes.h: glib_probes.d
< $@.tmp > $@ && rm -f $@.tmp
glib_probes.lo: glib_probes.d
- $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC $(DTRACE) -G -s $< -o $@
+ $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -G -s $< -o $@
BUILT_SOURCES += glib_probes.h glib_probes.lo
CLEANFILES += glib_probes.h glib_probes.h.tmp
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index 4c28acdff..78748e96c 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -119,7 +119,7 @@ gobject_probes.h: gobject_probes.d
< $@.tmp > $@ && rm -f $@.tmp
gobject_probes.lo: gobject_probes.d
- $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC $(DTRACE) -G -s $< -o $@
+ $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -G -s $< -o $@
BUILT_SOURCES += gobject_probes.h gobject_probes.lo
CLEANFILES += gobject_probes.h
--
2.21.0

@ -0,0 +1,27 @@
From fe803a6da0c7d73cd689d905258847384e11d1fd Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 17 Dec 2018 14:36:07 -0500
Subject: [PATCH] gdbus unix addresses test: don't g_debug when also testing
stdout
At the moment the gdbus-unix-addresses test will fail if
G_MESSAGES_DEBUG is set, since the test checks stdout, and the
test has a g_debug call.
This commit drops the g_debug call, which isn't that useful anyway.
---
gio/tests/gdbus-unix-addresses.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/gio/tests/gdbus-unix-addresses.c b/gio/tests/gdbus-unix-addresses.c
index e08328711..d020edd06 100644
--- a/gio/tests/gdbus-unix-addresses.c
+++ b/gio/tests/gdbus-unix-addresses.c
@@ -106,7 +106,6 @@ set_up_mock_dbus_launch (void)
{
path = g_strconcat (g_test_get_dir (G_TEST_BUILT), ":",
g_getenv ("PATH"), NULL);
- g_debug ("PATH=%s", path);
g_setenv ("PATH", path, TRUE);
/* libdbus won't even try X11 autolaunch if DISPLAY is unset; GDBus

@ -0,0 +1,613 @@
From aea538fe703652fd0a39b2ac9185133849cfdcc4 Mon Sep 17 00:00:00 2001
From: Thomas Jost <schnouki@schnouki.net>
Date: Thu, 13 Dec 2018 03:06:02 -0800
Subject: [PATCH] gdbus-codegen: honor "Property.EmitsChangedSignal"
annotations
Co-Authored-by: Andy Holmes <andrew.g.r.holmes@gmail.com>
---
gio/gdbus-2.0/codegen/codegen.py | 18 ++++++++++-----
gio/gdbus-2.0/codegen/dbustypes.py | 7 ++++++
gio/tests/gdbus-test-codegen.c | 36 +++++++++++++++++++++++++-----
gio/tests/test-codegen.xml | 6 +++++
4 files changed, 56 insertions(+), 11 deletions(-)
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index f6892af95..442bd3f5d 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -638,61 +638,62 @@ class CodeGenerator:
'# include <gio/gunixfdlist.h>\n'
'#endif\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusArgInfo parent_struct;\n'
' gboolean use_gvariant;\n'
'} _ExtendedGDBusArgInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusMethodInfo parent_struct;\n'
' const gchar *signal_name;\n'
' gboolean pass_fdlist;\n'
'} _ExtendedGDBusMethodInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusSignalInfo parent_struct;\n'
' const gchar *signal_name;\n'
'} _ExtendedGDBusSignalInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusPropertyInfo parent_struct;\n'
' const gchar *hyphen_name;\n'
- ' gboolean use_gvariant;\n'
+ ' guint use_gvariant : 1;\n'
+ ' guint emits_changed_signal : 1;\n'
'} _ExtendedGDBusPropertyInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusInterfaceInfo parent_struct;\n'
' const gchar *hyphen_name;\n'
'} _ExtendedGDBusInterfaceInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' const _ExtendedGDBusPropertyInfo *info;\n'
' guint prop_id;\n'
' GValue orig_value; /* the value before the change */\n'
'} ChangedProperty;\n'
'\n'
'static void\n'
'_changed_property_free (ChangedProperty *data)\n'
'{\n'
' g_value_unset (&data->orig_value);\n'
' g_free (data);\n'
'}\n'
'\n')
self.outfile.write('static gboolean\n'
'_g_strv_equal0 (gchar **a, gchar **b)\n'
'{\n'
' gboolean ret = FALSE;\n'
' guint n;\n'
@@ -933,63 +934,67 @@ class CodeGenerator:
'\n')
# ---
if len(i.properties) > 0:
for p in i.properties:
if p.readable and p.writable:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
elif p.readable:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
elif p.writable:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
else:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
num_anno = self.generate_annotations('_%s_property_%s_annotation_info'%(i.name_lower, p.name_lower), p.annotations)
self.outfile.write('static const _ExtendedGDBusPropertyInfo _%s_property_info_%s =\n'
'{\n'
' {\n'
' -1,\n'
' (gchar *) "%s",\n'
' (gchar *) "%s",\n'
' %s,\n'%(i.name_lower, p.name_lower, p.name, p.arg.signature, access))
if num_anno == 0:
self.outfile.write(' NULL\n')
else:
self.outfile.write(' (GDBusAnnotationInfo **) &_%s_property_%s_annotation_info_pointers\n'%(i.name_lower, p.name_lower))
self.outfile.write(' },\n'
' "%s",\n'
%(p.name_hyphen))
if not utils.lookup_annotation(p.annotations, 'org.gtk.GDBus.C.ForceGVariant'):
- self.outfile.write(' FALSE\n')
+ self.outfile.write(' FALSE,\n')
else:
+ self.outfile.write(' TRUE,\n')
+ if p.emits_changed_signal:
self.outfile.write(' TRUE\n')
+ else:
+ self.outfile.write(' FALSE\n')
self.outfile.write('};\n'
'\n')
self.outfile.write('static const GDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
'{\n'%(i.name_lower))
for p in i.properties:
self.outfile.write(' &_%s_property_info_%s.parent_struct,\n'%(i.name_lower, p.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
num_anno = self.generate_annotations('_%s_annotation_info'%(i.name_lower), i.annotations)
self.outfile.write('static const _ExtendedGDBusInterfaceInfo _%s_interface_info =\n'
'{\n'
' {\n'
' -1,\n'
' (gchar *) "%s",\n'%(i.name_lower, i.name))
if len(i.methods) == 0:
self.outfile.write(' NULL,\n')
else:
self.outfile.write(' (GDBusMethodInfo **) &_%s_method_info_pointers,\n'%(i.name_lower))
if len(i.signals) == 0:
self.outfile.write(' NULL,\n')
else:
self.outfile.write(' (GDBusSignalInfo **) &_%s_signal_info_pointers,\n'%(i.name_lower))
if len(i.properties) == 0:
self.outfile.write(' NULL,\n')
else:
self.outfile.write(' (GDBusPropertyInfo **) &_%s_property_info_pointers,\n'%(i.name_lower))
if num_anno == 0:
@@ -2568,68 +2573,71 @@ class CodeGenerator:
# this allows use of g_object_freeze_notify()/g_object_thaw_notify() ...
# This is useful when updating several properties from another thread than
# where the idle will be emitted from
self.outfile.write('static void\n'
'%s_skeleton_notify (GObject *object,\n'
' GParamSpec *pspec G_GNUC_UNUSED)\n'
'{\n'
' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
' g_mutex_lock (&skeleton->priv->lock);\n'
' if (skeleton->priv->changed_properties != NULL &&\n'
' skeleton->priv->changed_properties_idle_source == NULL)\n'
' {\n'
' skeleton->priv->changed_properties_idle_source = g_idle_source_new ();\n'
' g_source_set_priority (skeleton->priv->changed_properties_idle_source, G_PRIORITY_DEFAULT);\n'
' g_source_set_callback (skeleton->priv->changed_properties_idle_source, _%s_emit_changed, g_object_ref (skeleton), (GDestroyNotify) g_object_unref);\n'
' g_source_set_name (skeleton->priv->changed_properties_idle_source, "[generated] _%s_emit_changed");\n'
' g_source_attach (skeleton->priv->changed_properties_idle_source, skeleton->priv->context);\n'
' g_source_unref (skeleton->priv->changed_properties_idle_source);\n'
' }\n'
' g_mutex_unlock (&skeleton->priv->lock);\n'
'}\n'
'\n'
%(i.name_lower, i.camel_name, i.ns_upper, i.name_upper, i.name_lower, i.name_lower))
self.outfile.write('static void\n'
'%s_skeleton_set_property (GObject *object,\n'
' guint prop_id,\n'
' const GValue *value,\n'
' GParamSpec *pspec)\n'
'{\n'%(i.name_lower))
- self.outfile.write(' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
+ self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
+ ' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
' g_mutex_lock (&skeleton->priv->lock);\n'
' g_object_freeze_notify (object);\n'
' if (!_g_value_equal (value, &skeleton->priv->properties[prop_id - 1]))\n'
' {\n'
- ' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL)\n'
- ' _%s_schedule_emit_changed (skeleton, (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
+ ' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL &&\n'
+ ' info->emits_changed_signal)\n'
+ ' _%s_schedule_emit_changed (skeleton, info, prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
' g_value_copy (value, &skeleton->priv->properties[prop_id - 1]);\n'
' g_object_notify_by_pspec (object, pspec);\n'
' }\n'
' g_mutex_unlock (&skeleton->priv->lock);\n'
' g_object_thaw_notify (object);\n'
%(i.camel_name, i.ns_upper, i.name_upper, len(i.properties), i.name_lower, i.name_lower))
self.outfile.write('}\n'
'\n')
self.outfile.write('static void\n'
'%s_skeleton_init (%sSkeleton *skeleton)\n'
'{\n'
'#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38\n'
' skeleton->priv = %s_skeleton_get_instance_private (skeleton);\n'
'#else\n'
' skeleton->priv = G_TYPE_INSTANCE_GET_PRIVATE (skeleton, %sTYPE_%s_SKELETON, %sSkeletonPrivate);\n'
'#endif\n\n'
%(i.name_lower, i.camel_name,
i.name_lower,
i.ns_upper, i.name_upper, i.camel_name))
self.outfile.write(' g_mutex_init (&skeleton->priv->lock);\n')
self.outfile.write(' skeleton->priv->context = g_main_context_ref_thread_default ();\n')
if len(i.properties) > 0:
self.outfile.write(' skeleton->priv->properties = g_new0 (GValue, %d);\n'%(len(i.properties)))
n = 0
for p in i.properties:
self.outfile.write(' g_value_init (&skeleton->priv->properties[%d], %s);\n'%(n, p.arg.gtype))
n += 1
self.outfile.write('}\n'
'\n')
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
index bfc69f596..359880ff7 100644
--- a/gio/gdbus-2.0/codegen/dbustypes.py
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
@@ -300,89 +300,96 @@ class Signal:
arg_count = 0
for a in self.args:
a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
arg_count += 1
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
class Property:
def __init__(self, name, signature, access):
self.name = name
self.signature = signature
self.access = access
self.annotations = []
self.arg = Arg('value', self.signature)
self.arg.annotations = self.annotations
self.readable = False
self.writable = False
if self.access == 'readwrite':
self.readable = True
self.writable = True
elif self.access == 'read':
self.readable = True
elif self.access == 'write':
self.writable = True
else:
print_error('Invalid access type "{}"'.format(self.access))
self.doc_string = ''
self.since = ''
self.deprecated = False
+ self.emits_changed_signal = True
def post_process(self, interface_prefix, cns, cns_upper, cns_lower, containing_iface):
if len(self.doc_string) == 0:
self.doc_string = utils.lookup_docs(self.annotations)
if len(self.since) == 0:
self.since = utils.lookup_since(self.annotations)
if len(self.since) == 0:
self.since = containing_iface.since
name = self.name
overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name')
if utils.is_ugly_case(overridden_name):
self.name_lower = overridden_name.lower()
else:
if overridden_name:
name = overridden_name
self.name_lower = utils.camel_case_to_uscore(name).lower().replace('-', '_')
self.name_hyphen = self.name_lower.replace('_', '-')
# don't clash with the GType getter, e.g.: GType foo_bar_get_type (void); G_GNUC_CONST
if self.name_lower == 'type':
self.name_lower = 'type_'
# recalculate arg
self.arg.annotations = self.annotations
self.arg.post_process(interface_prefix, cns, cns_upper, cns_lower, 0)
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ # FIXME: for now we only support 'false' and 'const' on the signal itself, see #674913 and
+ # http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
+ # for details
+ if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Property.EmitsChangedSignal') in ('false', 'const'):
+ self.emits_changed_signal = False
+
class Interface:
def __init__(self, name):
self.name = name
self.methods = []
self.signals = []
self.properties = []
self.annotations = []
self.doc_string = ''
self.doc_string_brief = ''
self.since = ''
self.deprecated = False
def post_process(self, interface_prefix, c_namespace):
if len(self.doc_string) == 0:
self.doc_string = utils.lookup_docs(self.annotations)
if len(self.doc_string_brief) == 0:
self.doc_string_brief = utils.lookup_brief_docs(self.annotations)
if len(self.since) == 0:
self.since = utils.lookup_since(self.annotations)
if len(c_namespace) > 0:
if utils.is_ugly_case(c_namespace):
cns = c_namespace.replace('_', '')
cns_upper = c_namespace.upper() + '_'
cns_lower = c_namespace.lower() + '_'
else:
cns = c_namespace
cns_upper = utils.camel_case_to_uscore(c_namespace).upper() + '_'
cns_lower = utils.camel_case_to_uscore(c_namespace).lower() + '_'
else:
diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c
index 1c4e83c4c..c906d05ae 100644
--- a/gio/tests/gdbus-test-codegen.c
+++ b/gio/tests/gdbus-test-codegen.c
@@ -1740,103 +1740,127 @@ on_object_proxy_added (GDBusObjectManagerClient *manager,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_object_proxy_added_signals += 1;
g_signal_connect (object_proxy,
"interface-added",
G_CALLBACK (on_interface_added),
om_data);
g_signal_connect (object_proxy,
"interface-removed",
G_CALLBACK (on_interface_removed),
om_data);
}
static void
on_object_proxy_removed (GDBusObjectManagerClient *manager,
GDBusObjectProxy *object_proxy,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_object_proxy_removed_signals += 1;
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
G_CALLBACK (on_interface_added),
om_data), ==, 1);
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
G_CALLBACK (on_interface_removed),
om_data), ==, 1);
}
static void
-property_d_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+property_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
{
gboolean *changed = user_data;
*changed = TRUE;
}
static void
om_check_property_and_signal_emission (GMainLoop *loop,
FooiGenBar *skeleton,
FooiGenBar *proxy)
{
gboolean d_changed = FALSE;
+ gboolean quiet_changed = FALSE;
+ gboolean quiet_too_changed = FALSE;
guint handler;
/* First PropertiesChanged */
g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 0);
g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 0);
foo_igen_bar_set_i (skeleton, 1);
_g_assert_property_notify (proxy, "i");
g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 1);
g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 1);
/* Double-check the gdouble case */
g_assert_cmpfloat (foo_igen_bar_get_d (skeleton), ==, 0.0);
g_assert_cmpfloat (foo_igen_bar_get_d (proxy), ==, 0.0);
foo_igen_bar_set_d (skeleton, 1.0);
_g_assert_property_notify (proxy, "d");
/* Verify that re-setting it to the same value doesn't cause a
* notify on the proxy, by taking advantage of the fact that
* notifications are serialized.
*/
handler = g_signal_connect (proxy, "notify::d",
- G_CALLBACK (property_d_changed), &d_changed);
+ G_CALLBACK (property_changed), &d_changed);
foo_igen_bar_set_d (skeleton, 1.0);
foo_igen_bar_set_i (skeleton, 2);
_g_assert_property_notify (proxy, "i");
g_assert (d_changed == FALSE);
g_signal_handler_disconnect (proxy, handler);
+ /* Verify that re-setting a property with the "EmitsChangedSignal"
+ * set to false doesn't emit a signal. */
+ handler = g_signal_connect (proxy, "notify::quiet",
+ G_CALLBACK (property_changed), &quiet_changed);
+ foo_igen_bar_set_quiet (skeleton, "hush!");
+ foo_igen_bar_set_i (skeleton, 3);
+ _g_assert_property_notify (proxy, "i");
+ g_assert (quiet_changed == FALSE);
+ g_assert_cmpstr (foo_igen_bar_get_quiet (skeleton), ==, "hush!");
+ g_signal_handler_disconnect (proxy, handler);
+
+ /* Also verify that re-setting a property with the "EmitsChangedSignal"
+ * set to 'const' doesn't emit a signal. */
+ handler = g_signal_connect (proxy, "notify::quiet-too",
+ G_CALLBACK (property_changed), &quiet_changed);
+ foo_igen_bar_set_quiet_too (skeleton, "hush too!");
+ foo_igen_bar_set_i (skeleton, 4);
+ _g_assert_property_notify (proxy, "i");
+ g_assert (quiet_too_changed == FALSE);
+ g_assert_cmpstr (foo_igen_bar_get_quiet_too (skeleton), ==, "hush too!");
+ g_signal_handler_disconnect (proxy, handler);
+
/* Then just a regular signal */
foo_igen_bar_emit_another_signal (skeleton, "word");
_g_assert_signal_received (proxy, "another-signal");
}
static void
check_object_manager (void)
{
FooiGenObjectSkeleton *o = NULL;
FooiGenObjectSkeleton *o2 = NULL;
FooiGenObjectSkeleton *o3 = NULL;
GDBusInterfaceSkeleton *i;
GDBusConnection *c;
GDBusObjectManagerServer *manager = NULL;
GDBusNodeInfo *info;
GError *error;
GMainLoop *loop;
OMData *om_data = NULL;
guint om_signal_id = -1;
GDBusObjectManager *pm = NULL;
GList *object_proxies;
GList *proxies;
GDBusObject *op;
GDBusProxy *p;
FooiGenBar *bar_skeleton;
GDBusInterface *iface;
gchar *path, *name, *name_owner;
GDBusConnection *c2;
GDBusObjectManagerClientFlags flags;
@@ -2124,73 +2148,73 @@ check_object_manager (void)
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
/* -------------------------------------------------- */
/* create a new object with two interfaces */
o2 = foo_igen_object_skeleton_new ("/managed/second");
i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
bar_skeleton = FOO_IGEN_BAR (i); /* save for later test */
foo_igen_object_skeleton_set_bar (o2, FOO_IGEN_BAR (i));
g_clear_object (&i);
i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ());
foo_igen_object_skeleton_set_bat (o2, FOO_IGEN_BAT (i));
g_clear_object (&i);
/* ... add it */
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o2));
/* ... check we get the InterfacesAdded with _two_ interfaces */
om_data->state = 101;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 102);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* -------------------------------------------------- */
/* Now that we have a couple of objects with interfaces, check
* that ObjectManager.GetManagedObjects() works
*/
om_check_get_all (c, loop,
- "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'quiet': <''>, 'quiet_too': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
/* Set connection to NULL, causing everything to be unexported.. verify this.. and
* then set the connection back.. and then check things still work
*/
g_dbus_object_manager_server_set_connection (manager, NULL);
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
g_dbus_node_info_unref (info);
g_dbus_object_manager_server_set_connection (manager, c);
om_check_get_all (c, loop,
- "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'quiet': <''>, 'quiet_too': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
/* Also check that the ObjectManagerClient returns these objects - and
* that they are of the right GType cf. what was requested via
* the generated ::get-proxy-type signal handler
*/
object_proxies = g_dbus_object_manager_get_objects (pm);
g_assert (g_list_length (object_proxies) == 2);
g_list_free_full (object_proxies, g_object_unref);
op = g_dbus_object_manager_get_object (pm, "/managed/first");
g_assert (op != NULL);
g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
proxies = g_dbus_object_get_interfaces (op);
g_assert (g_list_length (proxies) == 1);
g_list_free_full (proxies, g_object_unref);
p = G_DBUS_PROXY (foo_igen_object_get_com_acme_coyote (FOO_IGEN_OBJECT (op)));
g_assert (p != NULL);
g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_COM_ACME_COYOTE_PROXY);
g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_COM_ACME_COYOTE));
g_clear_object (&p);
p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
g_assert (p == NULL);
g_clear_object (&op);
/* -- */
op = g_dbus_object_manager_get_object (pm, "/managed/second");
g_assert (op != NULL);
g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
proxies = g_dbus_object_get_interfaces (op);
diff --git a/gio/tests/test-codegen.xml b/gio/tests/test-codegen.xml
index 885a21f77..39d8769c7 100644
--- a/gio/tests/test-codegen.xml
+++ b/gio/tests/test-codegen.xml
@@ -79,60 +79,66 @@
<arg type="aay" name="array_of_bytestrings" />
<arg type="a{s(ii)}" name="dict_s_to_pairs" />
</signal>
<signal name="AnotherSignal">
<arg type="s" name="word" />
</signal>
<property name="y" type="y" access="readwrite">
<annotation name="org.gtk.GDBus.DocString" value="&lt;para&gt;Property docs, yah...&lt;/para&gt;&lt;para&gt;Second paragraph.&lt;/para&gt;"/>
</property>
<property name="b" type="b" access="readwrite"/>
<property name="n" type="n" access="readwrite"/>
<property name="q" type="q" access="readwrite"/>
<property name="i" type="i" access="readwrite"/>
<property name="u" type="u" access="readwrite"/>
<property name="x" type="x" access="readwrite"/>
<property name="t" type="t" access="readwrite"/>
<property name="d" type="d" access="readwrite"/>
<property name="s" type="s" access="readwrite"/>
<property name="o" type="o" access="readwrite"/>
<property name="g" type="g" access="readwrite"/>
<property name="ay" type="ay" access="readwrite"/>
<property name="as" type="as" access="readwrite"/>
<property name="aay" type="aay" access="readwrite"/>
<property name="ao" type="ao" access="readwrite"/>
<property name="ag" type="ag" access="readwrite"/>
<property name="FinallyNormalName" type="s" access="readwrite"/>
<property name="ReadonlyProperty" type="s" access="read"/>
<property name="WriteonlyProperty" type="s" access="write"/>
+ <property name="quiet" type="s" access="readwrite">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+ <property name="quiet_too" type="s" access="readwrite">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
+ </property>
<!-- unset properties -->
<property name="unset_i" type="i" access="readwrite"/>
<property name="unset_d" type="d" access="readwrite"/>
<property name="unset_s" type="s" access="readwrite"/>
<property name="unset_o" type="o" access="readwrite"/>
<property name="unset_g" type="g" access="readwrite"/>
<property name="unset_ay" type="ay" access="readwrite"/>
<property name="unset_as" type="as" access="readwrite"/>
<property name="unset_ao" type="ao" access="readwrite"/>
<property name="unset_ag" type="ag" access="readwrite"/>
<property name="unset_struct" type="(idsogayasaoag)" access="readwrite"/>
</interface> <!-- End org.project.Bar -->
<!-- Namespaced -->
<interface name="org.project.Bar.Frobnicator">
<method name="RandomMethod"/>
</interface>
<!-- Empty -->
<interface name="org.project.Baz">
</interface>
<!-- Outside D-Bus prefix -->
<interface name="com.acme.Coyote">
<method name="Run"/>
<method name="Sleep"/>
<method name="Attack"/>
<signal name="Surprised"/>
<property name="Mood" type="s" access="read"/>
--
2.21.0

@ -0,0 +1,702 @@
From 9e5a53d576765819d1c7c233515b9f6e5d77eb61 Mon Sep 17 00:00:00 2001
From: Emmanuele Bassi <ebassi@gnome.org>
Date: Wed, 17 Jan 2018 16:38:45 +0000
Subject: [PATCH] Add reference counting types
We have a common pattern for reference counting in GLib, but we always
implement it with ad hoc code. This is a good chance at trying to
standardise the implementation and make it public, so that other code
using GLib can take advantage of shared behaviour and semantics.
Instead of simply taking an integer variable, we should create type
aliases, to immediately distinguish the reference counting semantics of
the code; we can handle mixing atomic reference counting with a
non-atomic type (and vice versa) by using differently signed values for
the atomic and non-atomic cases.
The gatomicrefcount type is modelled on the Linux kernel refcount_t
type; the grefcount type is added to let single-threaded code bases to
avoid paying the price of atomic memory barriers on reference counting
operations.
---
docs/reference/glib/glib-docs.xml | 1 +
docs/reference/glib/glib-sections.txt | 15 ++
glib/Makefile.am | 2 +
glib/glib.h | 1 +
glib/grefcount.c | 285 ++++++++++++++++++++++++++
glib/grefcount.h | 52 +++++
glib/gtypes.h | 3 +
glib/meson.build | 2 +
8 files changed, 361 insertions(+)
create mode 100644 glib/grefcount.c
create mode 100644 glib/grefcount.h
diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml
index a0716c1727..26cdafb67b 100644
--- a/docs/reference/glib/glib-docs.xml
+++ b/docs/reference/glib/glib-docs.xml
@@ -119,6 +119,7 @@
<xi:include href="xml/gvariant.xml"/>
<xi:include href="gvariant-varargs.xml"/>
<xi:include href="gvariant-text.xml"/>
+ <xi:include href="xml/refcount.xml"/>
</chapter>
<chapter id="deprecated">
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 0183b0898a..331d92c75f 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -3449,3 +3449,18 @@ g_hostname_is_ip_address
g_uuid_string_is_valid
g_uuid_string_random
</SECTION>
+
+<SECTION>
+<FILE>refcount</FILE>
+grefcount
+g_ref_count_init
+g_ref_count_inc
+g_ref_count_dec
+g_ref_count_compare
+<SUBSECTION>
+gatomicrefcount
+g_atomic_ref_count_init
+g_atomic_ref_count_inc
+g_atomic_ref_count_dec
+g_atomic_ref_count_compare
+</SECTION>
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 0497061265..4d04e09daa 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -149,6 +149,7 @@ libglib_2_0_la_SOURCES = \
gquark.c \
gqueue.c \
grand.c \
+ grefcount.c \
gregex.c \
gscanner.c \
gscripttable.h \
@@ -284,6 +285,7 @@ glibsubinclude_HEADERS = \
gquark.h \
gqueue.h \
grand.h \
+ grefcount.h \
gregex.h \
gscanner.h \
gsequence.h \
diff --git a/glib/glib.h b/glib/glib.h
index 4f5a7f702f..84299c4f90 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -69,6 +69,7 @@
#include <glib/gquark.h>
#include <glib/gqueue.h>
#include <glib/grand.h>
+#include <glib/grefcount.h>
#include <glib/gregex.h>
#include <glib/gscanner.h>
#include <glib/gsequence.h>
diff --git a/glib/grefcount.c b/glib/grefcount.c
new file mode 100644
index 0000000000..10e35a217d
--- /dev/null
+++ b/glib/grefcount.c
@@ -0,0 +1,285 @@
+/* grefcount.c: Reference counting
+ *
+ * Copyright 2018 Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:refcount
+ * @Title: Reference counting
+ * @Short_description: Reference counting types and functions
+ *
+ * Reference counting is a garbage collection mechanism that is based on
+ * assigning a counter to a data type, or any memory area; the counter is
+ * increased whenever a new reference to that data type is acquired, and
+ * decreased whenever the reference is released. Once the last reference
+ * is released, the resources associated to that data type are freed.
+ *
+ * GLib uses reference counting in many of its data types, and provides
+ * the #grefcount and #gatomicrefcount types to implement safe and atomic
+ * reference counting semantics in new data types.
+ *
+ * It is important to note that #grefcount and #gatomicrefcount should be
+ * considered completely opaque types; you should always use the provided
+ * API to increase and decrease the counters, and you should never check
+ * their content directly, or compare their content with other values.
+ *
+ * Since: 2.58
+ */
+
+#include "config.h"
+
+#include "grefcount.h"
+
+#include "gatomic.h"
+#include "gmessages.h"
+
+/**
+ * grefcount:
+ *
+ * A type for implementing non-atomic reference count semantics.
+ *
+ * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
+ * increase the counter, and g_ref_count_dec() to decrease it.
+ *
+ * It is safe to use #grefcount only if you're expecting to operate
+ * on the reference counter from a single thread. It is entirely up
+ * to you to ensure that all reference count changes happen in the
+ * same thread.
+ *
+ * See also: #gatomicrefcount
+ *
+ * Since: 2.58
+ */
+
+/**
+ * gatomicrefcount:
+ *
+ * A type for implementing atomic reference count semantics.
+ *
+ * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
+ * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
+ *
+ * It is safe to use #gatomicrefcount if you're expecting to operate on the
+ * reference counter from multiple threads.
+ *
+ * See also: #grefcount
+ *
+ * Since: 2.58
+ */
+
+/**
+ * g_ref_count_init:
+ * @rc: the address of a reference count variable
+ *
+ * Initializes a reference count variable.
+ *
+ * Since: 2.58
+ */
+void
+g_ref_count_init (grefcount *rc)
+{
+ g_return_if_fail (rc != NULL);
+
+ /* Non-atomic refcounting is implemented using the negative range
+ * of signed integers:
+ *
+ * G_MININT Z¯< 0 > Z⁺ G_MAXINT
+ * |----------------------------|----------------------------|
+ *
+ * Acquiring a reference moves us towards MININT, and releasing a
+ * reference moves us towards 0.
+ */
+ *rc = -1;
+}
+
+/**
+ * g_ref_count_inc:
+ * @rc: the address of a reference count variable
+ *
+ * Increases the reference count.
+ *
+ * Since: 2.58
+ */
+void
+g_ref_count_inc (grefcount *rc)
+{
+ grefcount rrc;
+
+ g_return_if_fail (rc != NULL);
+
+ rrc = *rc;
+
+ g_return_if_fail (rrc < 0);
+
+ /* Check for saturation */
+ if (rrc == G_MININT)
+ {
+ g_critical ("Reference count %p has reached saturation", rc);
+ return;
+ }
+
+ rrc -= 1;
+
+ *rc = rrc;
+}
+
+/**
+ * g_ref_count_dec:
+ * @rc: the address of a reference count variable
+ *
+ * Decreases the reference count.
+ *
+ * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
+ *
+ * Since: 2.58
+ */
+gboolean
+g_ref_count_dec (grefcount *rc)
+{
+ grefcount rrc;
+
+ g_return_val_if_fail (rc != NULL, FALSE);
+
+ rrc = *rc;
+
+ g_return_val_if_fail (rrc < 0, FALSE);
+
+ rrc += 1;
+ if (rrc == 0)
+ return TRUE;
+
+ *rc = rrc;
+
+ return FALSE;
+}
+
+/**
+ * g_ref_count_compare:
+ * @rc: the address of a reference count variable
+ * @val: the value to compare
+ *
+ * Compares the current value of @rc with @val.
+ *
+ * Returns: %TRUE if the reference count is the same
+ * as the given value
+ *
+ * Since: 2.58
+ */
+gboolean
+g_ref_count_compare (grefcount *rc,
+ gint val)
+{
+ grefcount rrc;
+
+ g_return_val_if_fail (rc != NULL, FALSE);
+ g_return_val_if_fail (val >= 0, FALSE);
+
+ rrc = *rc;
+
+ if (val == G_MAXINT)
+ return rrc == G_MININT;
+
+ return rrc == -val;
+}
+
+/**
+ * g_atomic_ref_count_init:
+ * @arc: the address of an atomic reference count variable
+ *
+ * Atomically initializes a reference count variable.
+ *
+ * Since: 2.58
+ */
+void
+g_atomic_ref_count_init (gatomicrefcount *arc)
+{
+ g_return_if_fail (arc != NULL);
+
+ /* Atomic refcounting is implemented using the positive range
+ * of signed integers:
+ *
+ * G_MININT Z¯< 0 > Z⁺ G_MAXINT
+ * |----------------------------|----------------------------|
+ *
+ * Acquiring a reference moves us towards MAXINT, and releasing a
+ * reference moves us towards 0.
+ */
+ g_atomic_int_set (arc, 1);
+}
+
+/**
+ * g_atomic_ref_count_inc:
+ * @arc: the address of an atomic reference count variable
+ *
+ * Atomically increases the reference count.
+ *
+ * Since: 2.58
+ */
+void
+g_atomic_ref_count_inc (gatomicrefcount *arc)
+{
+ g_return_if_fail (arc != NULL);
+ g_return_if_fail (g_atomic_int_get (arc) > 0);
+
+ if (g_atomic_int_get (arc) == G_MAXINT)
+ {
+ g_critical ("Reference count has reached saturation");
+ return;
+ }
+
+ g_atomic_int_inc (arc);
+}
+
+/**
+ * g_atomic_ref_count_dec:
+ * @arc: the address of an atomic reference count variable
+ *
+ * Atomically decreases the reference count.
+ *
+ * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
+ *
+ * Since: 2.58
+ */
+gboolean
+g_atomic_ref_count_dec (gatomicrefcount *arc)
+{
+ g_return_val_if_fail (arc != NULL, FALSE);
+ g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
+
+ return g_atomic_int_dec_and_test (arc);
+}
+
+/**
+ * g_atomic_ref_count_compare:
+ * @arc: the address of an atomic reference count variable
+ * @val: the value to compare
+ *
+ * Atomically compares the current value of @arc with @val.
+ *
+ * Returns: %TRUE if the reference count is the same
+ * as the given value
+ *
+ * Since: 2.58
+ */
+gboolean
+g_atomic_ref_count_compare (gatomicrefcount *arc,
+ gint val)
+{
+ g_return_val_if_fail (arc != NULL, FALSE);
+ g_return_val_if_fail (val >= 0, FALSE);
+
+ return g_atomic_int_get (arc) == val;
+}
diff --git a/glib/grefcount.h b/glib/grefcount.h
new file mode 100644
index 0000000000..b24c71e8cb
--- /dev/null
+++ b/glib/grefcount.h
@@ -0,0 +1,52 @@
+/* grefcount.h: Reference counting
+ *
+ * Copyright 2018 Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GREFCOUNT_H__
+#define __GREFCOUNT_H__
+
+#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+GLIB_AVAILABLE_IN_2_56
+void g_ref_count_init (grefcount *rc);
+GLIB_AVAILABLE_IN_2_56
+void g_ref_count_inc (grefcount *rc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_ref_count_dec (grefcount *rc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_ref_count_compare (grefcount *rc,
+ gint val);
+
+GLIB_AVAILABLE_IN_2_56
+void g_atomic_ref_count_init (gatomicrefcount *arc);
+GLIB_AVAILABLE_IN_2_56
+void g_atomic_ref_count_inc (gatomicrefcount *arc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_atomic_ref_count_dec (gatomicrefcount *arc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_atomic_ref_count_compare (gatomicrefcount *arc,
+ gint val);
+
+G_END_DECLS
+
+#endif /* __GREFCOUNT_H__ */
diff --git a/glib/gtypes.h b/glib/gtypes.h
index 09d9bd1456..67adb7f1f8 100644
--- a/glib/gtypes.h
+++ b/glib/gtypes.h
@@ -510,6 +510,9 @@ struct _GTimeVal
glong tv_usec;
};
+typedef gint grefcount;
+typedef volatile gint gatomicrefcount;
+
G_END_DECLS
/* We prefix variable declarations so they can
diff --git a/glib/meson.build b/glib/meson.build
index 036d1f4d60..76d354c2a7 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -76,6 +76,7 @@ glib_sub_headers = files(
'gquark.h',
'gqueue.h',
'grand.h',
+ 'grefcount.h',
'gregex.h',
'gscanner.h',
'gsequence.h',
@@ -159,6 +160,7 @@ glib_sources = files(
'gquark.c',
'gqueue.c',
'grand.c',
+ 'grefcount.c',
'gregex.c',
'gscanner.c',
'gsequence.c',
--
GitLab
From 827c208cbf9cc0ef17b8c4531a40aafe1edc3f01 Mon Sep 17 00:00:00 2001
From: Emmanuele Bassi <ebassi@gnome.org>
Date: Mon, 4 Jun 2018 11:38:40 +0100
Subject: [PATCH] Use macros for refcount types API
If we're using GCC we can use __extension__ to inline the grefcount and
gatomicrefcount API, and avoid the function call.
These macros are only enabled if G_DISABLE_CHECKS is defined, as they
remove critical warnings when the reference counters achieve saturation.
---
glib/grefcount.c | 20 +++++++-------
glib/grefcount.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 10 deletions(-)
diff --git a/glib/grefcount.c b/glib/grefcount.c
index 10e35a217d..37085316b9 100644
--- a/glib/grefcount.c
+++ b/glib/grefcount.c
@@ -89,7 +89,7 @@
* Since: 2.58
*/
void
-g_ref_count_init (grefcount *rc)
+(g_ref_count_init) (grefcount *rc)
{
g_return_if_fail (rc != NULL);
@@ -114,7 +114,7 @@ g_ref_count_init (grefcount *rc)
* Since: 2.58
*/
void
-g_ref_count_inc (grefcount *rc)
+(g_ref_count_inc) (grefcount *rc)
{
grefcount rrc;
@@ -147,7 +147,7 @@ g_ref_count_inc (grefcount *rc)
* Since: 2.58
*/
gboolean
-g_ref_count_dec (grefcount *rc)
+(g_ref_count_dec) (grefcount *rc)
{
grefcount rrc;
@@ -179,8 +179,8 @@ g_ref_count_dec (grefcount *rc)
* Since: 2.58
*/
gboolean
-g_ref_count_compare (grefcount *rc,
- gint val)
+(g_ref_count_compare) (grefcount *rc,
+ gint val)
{
grefcount rrc;
@@ -204,7 +204,7 @@ g_ref_count_compare (grefcount *rc,
* Since: 2.58
*/
void
-g_atomic_ref_count_init (gatomicrefcount *arc)
+(g_atomic_ref_count_init) (gatomicrefcount *arc)
{
g_return_if_fail (arc != NULL);
@@ -229,7 +229,7 @@ g_atomic_ref_count_init (gatomicrefcount *arc)
* Since: 2.58
*/
void
-g_atomic_ref_count_inc (gatomicrefcount *arc)
+(g_atomic_ref_count_inc) (gatomicrefcount *arc)
{
g_return_if_fail (arc != NULL);
g_return_if_fail (g_atomic_int_get (arc) > 0);
@@ -254,7 +254,7 @@ g_atomic_ref_count_inc (gatomicrefcount *arc)
* Since: 2.58
*/
gboolean
-g_atomic_ref_count_dec (gatomicrefcount *arc)
+(g_atomic_ref_count_dec) (gatomicrefcount *arc)
{
g_return_val_if_fail (arc != NULL, FALSE);
g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
@@ -275,8 +275,8 @@ g_atomic_ref_count_dec (gatomicrefcount *arc)
* Since: 2.58
*/
gboolean
-g_atomic_ref_count_compare (gatomicrefcount *arc,
- gint val)
+(g_atomic_ref_count_compare) (gatomicrefcount *arc,
+ gint val)
{
g_return_val_if_fail (arc != NULL, FALSE);
g_return_val_if_fail (val >= 0, FALSE);
diff --git a/glib/grefcount.h b/glib/grefcount.h
index b24c71e8cb..dec9a5ffb8 100644
--- a/glib/grefcount.h
+++ b/glib/grefcount.h
@@ -47,6 +47,76 @@ GLIB_AVAILABLE_IN_2_58
gboolean g_atomic_ref_count_compare (gatomicrefcount *arc,
gint val);
+/* On GCC we can use __extension__ to inline the API without using
+ * ancillary functions; we only do this when disabling checks, as
+ * it disables warnings when saturating the reference counters
+ */
+#if defined(__GNUC__) && defined(G_DISABLE_CHECKS)
+
+# define g_ref_count_init(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ *(rc) = -1; \
+ }))
+
+# define g_ref_count_inc(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ if (*(rc) == G_MININT) ; else { \
+ *(rc) -= 1; \
+ } \
+ }))
+
+# define g_ref_count_dec(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ grefcount __rc = *(rc); \
+ __rc += 1; \
+ if (__rc == 0) ; else { \
+ *(rc) = __rc; \
+ } \
+ (gboolean) (__rc == 0); \
+ }))
+
+# define g_ref_count_compare(rc,val) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ (void) (0 ? *(rc) ^ (val) : 1); \
+ (gboolean) (*(rc) == -(val)); \
+ }))
+
+# define g_atomic_ref_count_init(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ g_atomic_int_set ((rc), 1); \
+ }))
+
+# define g_atomic_ref_count_inc(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ (void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
+ }))
+
+# define g_atomic_ref_count_dec(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ g_atomic_int_dec_and_test ((rc)); \
+ }))
+
+# define g_atomic_ref_count_compare(rc,val) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ (val) : 1); \
+ (gboolean) (g_atomic_int_get (rc) == (val)); \
+ }))
+
+#endif /* __GNUC__ && G_DISABLE_CHECKS */
+
G_END_DECLS
#endif /* __GREFCOUNT_H__ */
--
GitLab
From 09c149453ac969dedb1cb2d15d489d1dd81412bf Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Date: Sat, 13 Oct 2018 23:10:33 +0200
Subject: [PATCH] grefcount: add missing gatomic.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Without gatomic.h, build fails on:
In file included from garcbox.c:24:0:
garcbox.c: In function ‘g_atomic_rc_box_acquire’:
grefcount.h:101:13: error: implicit declaration of function ‘g_atomic_int_get’; did you mean ‘__atomic_store’? [-Werror=implicit-function-declaration]
(void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
^
garcbox.c:292:3: note: in expansion of macro ‘g_atomic_ref_count_inc’
g_atomic_ref_count_inc (&real_box->ref_count);
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
---
glib/grefcount.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/glib/grefcount.h b/glib/grefcount.h
index dec9a5ffb8..b6eced1b7d 100644
--- a/glib/grefcount.h
+++ b/glib/grefcount.h
@@ -23,6 +23,7 @@
#error "Only <glib.h> can be included directly."
#endif
+#include <glib/gatomic.h>
#include <glib/gtypes.h>
G_BEGIN_DECLS
--
GitLab

@ -0,0 +1,21 @@
From 521f9605e0ab019ec9a493153ca0c8fe4267d665 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 17 Dec 2018 15:46:10 -0500
Subject: [PATCH] spawn: add shebang line to script
downstream tools get confused when the script is missing a shebang
line, and having a shebang line doesn't hurt, so add one.
---
glib/tests/echo-script | 1 +
1 file changed, 1 insertion(+)
diff --git a/glib/tests/echo-script b/glib/tests/echo-script
index c732ed910..b609f2d39 100755
--- a/glib/tests/echo-script
+++ b/glib/tests/echo-script
@@ -1 +1,2 @@
+#!/bin/sh
echo "echo"
--
2.20.0

@ -0,0 +1,53 @@
From d8f8f4d637ce43f8699ba94c9b7648beda0ca174 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 23 May 2019 10:41:53 +0200
Subject: [PATCH] gfile: Limit access to files when copying
file_copy_fallback creates new files with default permissions and
set the correct permissions after the operation is finished. This
might cause that the files can be accessible by more users during
the operation than expected. Use G_FILE_CREATE_PRIVATE for the new
files to limit access to those files.
---
gio/gfile.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index 24b136d80..74b58047c 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3284,12 +3284,12 @@ file_copy_fallback (GFile *source,
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION,
- info,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE, info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, 0, info,
+ FALSE, G_FILE_CREATE_PRIVATE, info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
@@ -3297,12 +3297,13 @@ file_copy_fallback (GFile *source,
out = (GOutputStream *)g_file_replace (destination,
NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE,
cancellable, error);
}
else
{
- out = (GOutputStream *)g_file_create (destination, 0, cancellable, error);
+ out = (GOutputStream *)g_file_create (destination, G_FILE_CREATE_PRIVATE, cancellable, error);
}
if (!out)
--
2.21.0

@ -0,0 +1,38 @@
From 32ed752130bcbccc008819a7f1ea27651c601ee2 Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen@redhat.com>
Date: Tue, 22 Jan 2019 13:26:31 -0500
Subject: [PATCH 9/9] keyfile settings: Use tighter permissions
When creating directories, create them with 700 permissions,
instead of 777.
Closes: #1658
---
gio/gkeyfilesettingsbackend.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
index f5358818e..3d793f5a8 100644
--- a/gio/gkeyfilesettingsbackend.c
+++ b/gio/gkeyfilesettingsbackend.c
@@ -113,7 +113,8 @@ g_keyfile_settings_backend_keyfile_write (GKeyfileSettingsBackend *kfsb)
contents = g_key_file_to_data (kfsb->keyfile, &length, NULL);
g_file_replace_contents (kfsb->file, contents, length, NULL, FALSE,
- G_FILE_CREATE_REPLACE_DESTINATION,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE,
NULL, NULL, NULL);
compute_checksum (kfsb->digest, contents, length);
@@ -708,7 +709,7 @@ g_keyfile_settings_backend_constructed (GObject *object)
kfsb->permission = g_simple_permission_new (TRUE);
kfsb->dir = g_file_get_parent (kfsb->file);
- g_file_make_directory_with_parents (kfsb->dir, NULL, NULL);
+ g_mkdir_with_parents (g_file_peek_path (kfsb->dir), 0700);
kfsb->file_monitor = g_file_monitor (kfsb->file, G_FILE_MONITOR_NONE, NULL, NULL);
kfsb->dir_monitor = g_file_monitor (kfsb->dir, G_FILE_MONITOR_NONE, NULL, NULL);
--
2.28.0

@ -0,0 +1,129 @@
From 89b522ed31837cb2ac107a8961fbb0f2c7fc7ccb Mon Sep 17 00:00:00 2001
From: Krzesimir Nowak <qdlacz@gmail.com>
Date: Wed, 10 Feb 2021 23:51:07 +0100
Subject: [PATCH] gbytearray: Do not accept too large byte arrays
GByteArray uses guint for storing the length of the byte array, but it
also has a constructor (g_byte_array_new_take) that takes length as a
gsize. gsize may be larger than guint (64 bits for gsize vs 32 bits
for guint). It is possible to call the function with a value greater
than G_MAXUINT, which will result in silent length truncation. This
may happen as a result of unreffing GBytes into GByteArray, so rather
be loud about it.
(Test case tweaked by Philip Withnall.)
---
glib/garray.c | 6 ++++++
glib/gbytes.c | 4 ++++
glib/tests/bytes.c | 37 +++++++++++++++++++++++++++++++++++--
3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/glib/garray.c b/glib/garray.c
index aa3c04707..271d85ad8 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -1666,6 +1666,10 @@ g_byte_array_new (void)
* Create byte array containing the data. The data will be owned by the array
* and will be freed with g_free(), i.e. it could be allocated using g_strdup().
*
+ * Do not use it if @len is greater than %G_MAXUINT. #GByteArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
* Since: 2.32
*
* Returns: (transfer full): a new #GByteArray
@@ -1677,6 +1681,8 @@ g_byte_array_new_take (guint8 *data,
GByteArray *array;
GRealArray *real;
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
array = g_byte_array_new ();
real = (GRealArray *)array;
g_assert (real->data == NULL);
diff --git a/glib/gbytes.c b/glib/gbytes.c
index 5141170d7..635b79535 100644
--- a/glib/gbytes.c
+++ b/glib/gbytes.c
@@ -512,6 +512,10 @@ g_bytes_unref_to_data (GBytes *bytes,
* g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes(). In all
* other cases the data is copied.
*
+ * Do not use it if @bytes contains more than %G_MAXUINT
+ * bytes. #GByteArray stores the length of its data in #guint, which
+ * may be shorter than #gsize, that @bytes is using.
+ *
* Returns: (transfer full): a new mutable #GByteArray containing the same byte data
*
* Since: 2.32
diff --git a/glib/tests/bytes.c b/glib/tests/bytes.c
index 5ea5c2b35..42281307b 100644
--- a/glib/tests/bytes.c
+++ b/glib/tests/bytes.c
@@ -10,12 +10,12 @@
*/
#undef G_DISABLE_ASSERT
-#undef G_LOG_DOMAIN
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "glib.h"
+#include "glib/gstrfuncsprivate.h"
/* Keep in sync with glib/gbytes.c */
struct _GBytes
@@ -333,6 +333,38 @@ test_to_array_transferred (void)
g_byte_array_unref (array);
}
+static void
+test_to_array_transferred_oversize (void)
+{
+ g_test_message ("g_bytes_unref_to_array() can only take GBytes up to "
+ "G_MAXUINT in length; test that longer ones are rejected");
+
+ if (sizeof (guint) >= sizeof (gsize))
+ {
+ g_test_skip ("Skipping test as guint is not smaller than gsize");
+ }
+ else if (g_test_undefined ())
+ {
+ GByteArray *array = NULL;
+ GBytes *bytes = NULL;
+ gpointer data = g_memdup2 (NYAN, N_NYAN);
+ gsize len = ((gsize) G_MAXUINT) + 1;
+
+ bytes = g_bytes_new_take (data, len);
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed");
+ array = g_bytes_unref_to_array (g_steal_pointer (&bytes));
+ g_test_assert_expected_messages ();
+ g_assert_null (array);
+
+ g_free (data);
+ }
+ else
+ {
+ g_test_skip ("Skipping test as testing undefined behaviour is disabled");
+ }
+}
+
static void
test_to_array_two_refs (void)
{
@@ -407,7 +439,8 @@ main (int argc, char *argv[])
g_test_add_func ("/bytes/to-data/transfered", test_to_data_transferred);
g_test_add_func ("/bytes/to-data/two-refs", test_to_data_two_refs);
g_test_add_func ("/bytes/to-data/non-malloc", test_to_data_non_malloc);
- g_test_add_func ("/bytes/to-array/transfered", test_to_array_transferred);
+ g_test_add_func ("/bytes/to-array/transferred", test_to_array_transferred);
+ g_test_add_func ("/bytes/to-array/transferred-oversize", test_to_array_transferred_oversize);
g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs);
g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc);
g_test_add_func ("/bytes/null", test_null);
--
2.31.1

@ -0,0 +1,849 @@
From 7b46597384de916b4027ebaff662d06ff3ea2bc8 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:30:52 +0000
Subject: [PATCH 1/6] gstrfuncs: Add internal g_memdup2() function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This will replace the existing `g_memdup()` function for use within
GLib. It has an unavoidable security flaw of taking its `byte_size`
argument as a `guint` rather than as a `gsize`. Most callers will
expect it to be a `gsize`, and may pass in large values which could
silently be truncated, resulting in an undersize allocation compared
to what the caller expects.
This could lead to a classic buffer overflow vulnerability for many
callers of `g_memdup()`.
`g_memdup2()`, in comparison, takes its `byte_size` as a `gsize`.
Spotted by Kevin Backhouse of GHSL.
In GLib 2.68, `g_memdup2()` will be a new public API. In this version
for backport to older stable releases, its a new `static inline` API
in a private header, so that use of `g_memdup()` within GLib can be
fixed without adding a new API in a stable release series.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: CVE-2021-27219
Helps: GHSL-2021-045
Helps: #2319
(cherry picked from commit 5e5f75a77e399c638be66d74e5daa8caeb433e00)
---
docs/reference/glib/meson.build | 1 +
glib/gstrfuncsprivate.h | 55 +++++++++++++++++++++++++++++++++
glib/meson.build | 1 +
glib/tests/strfuncs.c | 23 ++++++++++++++
4 files changed, 80 insertions(+)
create mode 100644 glib/gstrfuncsprivate.h
diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build
index f0f915e96..1a3680941 100644
--- a/docs/reference/glib/meson.build
+++ b/docs/reference/glib/meson.build
@@ -20,6 +20,7 @@ if get_option('gtk_doc')
'gprintfint.h',
'gmirroringtable.h',
'gscripttable.h',
+ 'gstrfuncsprivate.h',
'glib-mirroring-tab',
'gnulib',
'pcre',
diff --git a/glib/gstrfuncsprivate.h b/glib/gstrfuncsprivate.h
new file mode 100644
index 000000000..85c88328a
--- /dev/null
+++ b/glib/gstrfuncsprivate.h
@@ -0,0 +1,55 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+/*
+ * g_memdup2:
+ * @mem: (nullable): the memory to copy.
+ * @byte_size: the number of bytes to copy.
+ *
+ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it
+ * from @mem. If @mem is %NULL it returns %NULL.
+ *
+ * This replaces g_memdup(), which was prone to integer overflows when
+ * converting the argument from a #gsize to a #guint.
+ *
+ * This static inline version is a backport of the new public API from
+ * GLib 2.68, kept internal to GLib for backport to older stable releases.
+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2319.
+ *
+ * Returns: (nullable): a pointer to the newly-allocated copy of the memory,
+ * or %NULL if @mem is %NULL.
+ * Since: 2.68
+ */
+static inline gpointer
+g_memdup2 (gconstpointer mem,
+ gsize byte_size)
+{
+ gpointer new_mem;
+
+ if (mem && byte_size != 0)
+ {
+ new_mem = g_malloc (byte_size);
+ memcpy (new_mem, mem, byte_size);
+ }
+ else
+ new_mem = NULL;
+
+ return new_mem;
+}
diff --git a/glib/meson.build b/glib/meson.build
index a2f9da81c..481fd06ff 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -167,6 +167,7 @@ glib_sources = files(
'gslist.c',
'gstdio.c',
'gstrfuncs.c',
+ 'gstrfuncsprivate.h',
'gstring.c',
'gstringchunk.c',
'gtestutils.c',
diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c
index 7e031bdb1..2aa252946 100644
--- a/glib/tests/strfuncs.c
+++ b/glib/tests/strfuncs.c
@@ -32,6 +32,8 @@
#include <string.h>
#include "glib.h"
+#include "gstrfuncsprivate.h"
+
#if defined (_MSC_VER) && (_MSC_VER <= 1800)
#define isnan(x) _isnan(x)
@@ -199,6 +201,26 @@ test_is_to_digit (void)
#undef TEST_DIGIT
}
+/* Testing g_memdup2() function with various positive and negative cases */
+static void
+test_memdup2 (void)
+{
+ gchar *str_dup = NULL;
+ const gchar *str = "The quick brown fox jumps over the lazy dog";
+
+ /* Testing negative cases */
+ g_assert_null (g_memdup2 (NULL, 1024));
+ g_assert_null (g_memdup2 (str, 0));
+ g_assert_null (g_memdup2 (NULL, 0));
+
+ /* Testing normal usage cases */
+ str_dup = g_memdup2 (str, strlen (str) + 1);
+ g_assert_nonnull (str_dup);
+ g_assert_cmpstr (str, ==, str_dup);
+
+ g_free (str_dup);
+}
+
static void
test_strdup (void)
{
@@ -1726,6 +1748,7 @@ main (int argc,
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/strfuncs/test-is-to-digit", test_is_to_digit);
+ g_test_add_func ("/strfuncs/memdup2", test_memdup2);
g_test_add_func ("/strfuncs/strdup", test_strdup);
g_test_add_func ("/strfuncs/strndup", test_strndup);
g_test_add_func ("/strfuncs/strdup-printf", test_strdup_printf);
--
2.31.1
From d6aab169954d9e6e77753dee68e1b3f5932f6dee Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:41:21 +0000
Subject: [PATCH 2/6] glib: Use g_memdup2() instead of g_memdup() in obvious
places
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Convert all the call sites which use `g_memdup()`s length argument
trivially (for example, by passing a `sizeof()` or an existing `gsize`
variable), so that they use `g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it
In particular, this fixes an overflow within `g_bytes_new()`, identified
as GHSL-2021-045 (aka CVE-2021-27219) by GHSL team member Kevin Backhouse.
Adapted for GLib 2.58 by Simon McVittie.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: CVE-2021-27219
Fixes: GHSL-2021-045
Helps: #2319
(cherry picked from commit 0736b7c1e7cf4232c5d7eb2b0fbfe9be81bd3baa)
[Backport to 2.58: Omit changes to ghash.c, will be a separate commit]
[Backport to 2.58: Omit changes to giochannel.c, not needed in this branch]
[Backport to 2.58: Omit changes to uri test, not needed in this branch]
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/gbytes.c | 6 ++++--
glib/gdir.c | 3 ++-
glib/gslice.c | 3 ++-
glib/gtestutils.c | 3 ++-
glib/gvariant.c | 7 ++++---
glib/gvarianttype.c | 3 ++-
glib/tests/array-test.c | 2 +-
glib/tests/option-context.c | 6 ++++--
8 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/glib/gbytes.c b/glib/gbytes.c
index 3b14a51cd..5141170d7 100644
--- a/glib/gbytes.c
+++ b/glib/gbytes.c
@@ -33,6 +33,8 @@
#include <string.h>
+#include "gstrfuncsprivate.h"
+
/**
* GBytes:
*
@@ -94,7 +96,7 @@ g_bytes_new (gconstpointer data,
{
g_return_val_if_fail (data != NULL || size == 0, NULL);
- return g_bytes_new_take (g_memdup (data, size), size);
+ return g_bytes_new_take (g_memdup2 (data, size), size);
}
/**
@@ -490,7 +492,7 @@ g_bytes_unref_to_data (GBytes *bytes,
* Copy: Non g_malloc (or compatible) allocator, or static memory,
* so we have to copy, and then unref.
*/
- result = g_memdup (bytes->data, bytes->size);
+ result = g_memdup2 (bytes->data, bytes->size);
*size = bytes->size;
g_bytes_unref (bytes);
}
diff --git a/glib/gdir.c b/glib/gdir.c
index cb4ad0b2f..9d955d57f 100644
--- a/glib/gdir.c
+++ b/glib/gdir.c
@@ -37,6 +37,7 @@
#include "gconvert.h"
#include "gfileutils.h"
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gtestutils.h"
#include "glibintl.h"
@@ -113,7 +114,7 @@ g_dir_open_with_errno (const gchar *path,
return NULL;
#endif
- return g_memdup (&dir, sizeof dir);
+ return g_memdup2 (&dir, sizeof dir);
}
/**
diff --git a/glib/gslice.c b/glib/gslice.c
index 454c8a602..8e2359515 100644
--- a/glib/gslice.c
+++ b/glib/gslice.c
@@ -45,6 +45,7 @@
#include "gmain.h"
#include "gmem.h" /* gslice.h */
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gutils.h"
#include "gtrashstack.h"
#include "gtestutils.h"
@@ -352,7 +353,7 @@ g_slice_get_config_state (GSliceConfig ckey,
array[i++] = allocator->contention_counters[address];
array[i++] = allocator_get_magazine_threshold (allocator, address);
*n_values = i;
- return g_memdup (array, sizeof (array[0]) * *n_values);
+ return g_memdup2 (array, sizeof (array[0]) * *n_values);
default:
return NULL;
}
diff --git a/glib/gtestutils.c b/glib/gtestutils.c
index 0447dcda5..14e071fce 100644
--- a/glib/gtestutils.c
+++ b/glib/gtestutils.c
@@ -49,6 +49,7 @@
#include "gpattern.h"
#include "grand.h"
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gtimer.h"
#include "gslice.h"
#include "gspawn.h"
@@ -3397,7 +3398,7 @@ g_test_log_extract (GTestLogBuffer *tbuffer)
if (p <= tbuffer->data->str + mlength)
{
g_string_erase (tbuffer->data, 0, mlength);
- tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg)));
+ tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup2 (&msg, sizeof (msg)));
return TRUE;
}
diff --git a/glib/gvariant.c b/glib/gvariant.c
index 8be9ce798..45a1a73dc 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -33,6 +33,7 @@
#include <string.h>
+#include "gstrfuncsprivate.h"
/**
* SECTION:gvariant
@@ -720,7 +721,7 @@ g_variant_new_variant (GVariant *value)
g_variant_ref_sink (value);
return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT,
- g_memdup (&value, sizeof value),
+ g_memdup2 (&value, sizeof value),
1, g_variant_is_trusted (value));
}
@@ -1224,7 +1225,7 @@ g_variant_new_fixed_array (const GVariantType *element_type,
return NULL;
}
- data = g_memdup (elements, n_elements * element_size);
+ data = g_memdup2 (elements, n_elements * element_size);
value = g_variant_new_from_data (array_type, data,
n_elements * element_size,
FALSE, g_free, data);
@@ -1901,7 +1902,7 @@ g_variant_dup_bytestring (GVariant *value,
if (length)
*length = size;
- return g_memdup (original, size + 1);
+ return g_memdup2 (original, size + 1);
}
/**
diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c
index c8433e65a..dbbf7d2d1 100644
--- a/glib/gvarianttype.c
+++ b/glib/gvarianttype.c
@@ -28,6 +28,7 @@
#include <string.h>
+#include "gstrfuncsprivate.h"
/**
* SECTION:gvarianttype
@@ -1174,7 +1175,7 @@ g_variant_type_new_tuple (const GVariantType * const *items,
g_assert (offset < sizeof buffer);
buffer[offset++] = ')';
- return (GVariantType *) g_memdup (buffer, offset);
+ return (GVariantType *) g_memdup2 (buffer, offset);
}
/**
--
2.31.1
From 7e2c2a07508a97b9d75e402afe4749b02a34dd8b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 18 Mar 2021 10:31:00 +0000
Subject: [PATCH 3/6] ghash: Use g_memdup2() instead of g_memdup()
Backport of part of commit 0736b7c1e7cf4232c5d7eb2b0fbfe9be81bd3baa
to the simpler structure of the GHashTable code in glib-2-58.
Helps: #2319
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/ghash.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/glib/ghash.c b/glib/ghash.c
index 6bb04a50d..608d136f4 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -34,6 +34,7 @@
#include "glib-private.h"
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gatomic.h"
#include "gtestutils.h"
#include "gslice.h"
@@ -967,7 +968,7 @@ g_hash_table_insert_node (GHashTable *hash_table,
* split the table.
*/
if (G_UNLIKELY (hash_table->keys == hash_table->values && hash_table->keys[node_index] != new_value))
- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
+ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
/* Step 3: Actually do the write */
hash_table->values[node_index] = new_value;
--
2.31.1
From 9e0c87610dccd1b0eaca28a3baa521ea6a24f46b Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:39:25 +0000
Subject: [PATCH 4/6] gobject: Use g_memdup2() instead of g_memdup() in obvious
places
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Convert all the call sites which use `g_memdup()`s length argument
trivially (for example, by passing a `sizeof()`), so that they use
`g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
(cherry picked from commit 6110caea45b235420b98cd41d845cc92238f6781)
---
gobject/gsignal.c | 3 ++-
gobject/gtype.c | 9 +++++----
gobject/gtypemodule.c | 3 ++-
gobject/tests/param.c | 4 +++-
4 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index b22dfcca8..92555eb60 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -28,6 +28,7 @@
#include <signal.h>
#include "gsignal.h"
+#include "gstrfuncsprivate.h"
#include "gtype-private.h"
#include "gbsearcharray.h"
#include "gvaluecollector.h"
@@ -1724,7 +1725,7 @@ g_signal_newv (const gchar *signal_name,
node->single_va_closure_is_valid = FALSE;
node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
node->n_params = n_params;
- node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
+ node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params);
node->return_type = return_type;
node->class_closure_bsa = NULL;
if (accumulator)
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 275a8b60b..9e663ce52 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -33,6 +33,7 @@
#include "glib-private.h"
#include "gconstructor.h"
+#include "gstrfuncsprivate.h"
#ifdef G_OS_WIN32
#include <windows.h>
@@ -1471,7 +1472,7 @@ type_add_interface_Wm (TypeNode *node,
iholder->next = iface_node_get_holders_L (iface);
iface_node_set_holders_W (iface, iholder);
iholder->instance_type = NODE_TYPE (node);
- iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
+ iholder->info = info ? g_memdup2 (info, sizeof (*info)) : NULL;
iholder->plugin = plugin;
/* create an iface entry for this type */
@@ -1732,7 +1733,7 @@ type_iface_retrieve_holder_info_Wm (TypeNode *iface,
INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
check_interface_info_I (iface, instance_type, &tmp_info);
- iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
+ iholder->info = g_memdup2 (&tmp_info, sizeof (tmp_info));
}
return iholder; /* we don't modify write lock upon returning NULL */
@@ -2013,10 +2014,10 @@ type_iface_vtable_base_init_Wm (TypeNode *iface,
IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
if (pentry)
- vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
+ vtable = g_memdup2 (pentry->vtable, iface->data->iface.vtable_size);
}
if (!vtable)
- vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
+ vtable = g_memdup2 (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
entry->vtable = vtable;
vtable->g_type = NODE_TYPE (iface);
vtable->g_instance_type = NODE_TYPE (node);
diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c
index c67f789b1..cf877bc0b 100644
--- a/gobject/gtypemodule.c
+++ b/gobject/gtypemodule.c
@@ -19,6 +19,7 @@
#include <stdlib.h>
+#include "gstrfuncsprivate.h"
#include "gtypeplugin.h"
#include "gtypemodule.h"
@@ -436,7 +437,7 @@ g_type_module_register_type (GTypeModule *module,
module_type_info->loaded = TRUE;
module_type_info->info = *type_info;
if (type_info->value_table)
- module_type_info->info.value_table = g_memdup (type_info->value_table,
+ module_type_info->info.value_table = g_memdup2 (type_info->value_table,
sizeof (GTypeValueTable));
return module_type_info->type;
diff --git a/gobject/tests/param.c b/gobject/tests/param.c
index 758289bf8..971cff162 100644
--- a/gobject/tests/param.c
+++ b/gobject/tests/param.c
@@ -2,6 +2,8 @@
#include <glib-object.h>
#include <stdlib.h>
+#include "gstrfuncsprivate.h"
+
static void
test_param_value (void)
{
@@ -851,7 +853,7 @@ main (int argc, char *argv[])
test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d",
data.change_this_flag, data.change_this_type,
data.use_this_flag, data.use_this_type);
- test_data = g_memdup (&data, sizeof (TestParamImplementData));
+ test_data = g_memdup2 (&data, sizeof (TestParamImplementData));
g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free);
g_free (test_path);
}
--
2.31.1
From d3f7a79540fc1e85eb82c2987e9f7e2dbd93ff74 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:37:56 +0000
Subject: [PATCH 5/6] gio: Use g_memdup2() instead of g_memdup() in obvious
places
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Convert all the call sites which use `g_memdup()`s length argument
trivially (for example, by passing a `sizeof()`), so that they use
`g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
(cherry picked from commit be8834340a2d928ece82025463ae23dee2c333d0)
---
gio/gdbusconnection.c | 5 +++--
gio/gdbusinterfaceskeleton.c | 3 ++-
gio/gfile.c | 7 ++++---
gio/gsettingsschema.c | 5 +++--
gio/gwin32registrykey.c | 8 +++++---
gio/tests/async-close-output-stream.c | 6 ++++--
gio/tests/gdbus-export.c | 5 +++--
gio/win32/gwinhttpfile.c | 9 +++++----
8 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 6f7e5fefc..117c8df35 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -119,6 +119,7 @@
#include "gasyncinitable.h"
#include "giostream.h"
#include "gasyncresult.h"
+#include "gstrfuncsprivate.h"
#include "gtask.h"
#ifdef G_OS_UNIX
@@ -3970,7 +3971,7 @@ _g_dbus_interface_vtable_copy (const GDBusInterfaceVTable *vtable)
/* Don't waste memory by copying padding - remember to update this
* when changing struct _GDBusInterfaceVTable in gdbusconnection.h
*/
- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
+ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
}
static void
@@ -3987,7 +3988,7 @@ _g_dbus_subtree_vtable_copy (const GDBusSubtreeVTable *vtable)
/* Don't waste memory by copying padding - remember to update this
* when changing struct _GDBusSubtreeVTable in gdbusconnection.h
*/
- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
+ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
}
static void
diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
index 96bd520aa..672604c49 100644
--- a/gio/gdbusinterfaceskeleton.c
+++ b/gio/gdbusinterfaceskeleton.c
@@ -27,6 +27,7 @@
#include "gdbusprivate.h"
#include "gdbusmethodinvocation.h"
#include "gdbusconnection.h"
+#include "gstrfuncsprivate.h"
#include "gtask.h"
#include "gioerror.h"
@@ -697,7 +698,7 @@ add_connection_locked (GDBusInterfaceSkeleton *interface_,
* properly before building the hooked_vtable, so we create it
* once at the last minute.
*/
- interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
+ interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
}
diff --git a/gio/gfile.c b/gio/gfile.c
index ff313ebf8..29ebaaa62 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -60,6 +60,7 @@
#include "gasyncresult.h"
#include "gioerror.h"
#include "glibintl.h"
+#include "gstrfuncsprivate.h"
/**
@@ -7734,7 +7735,7 @@ measure_disk_usage_progress (gboolean reporting,
g_main_context_invoke_full (g_task_get_context (task),
g_task_get_priority (task),
measure_disk_usage_invoke_progress,
- g_memdup (&progress, sizeof progress),
+ g_memdup2 (&progress, sizeof progress),
g_free);
}
@@ -7752,7 +7753,7 @@ measure_disk_usage_thread (GTask *task,
data->progress_callback ? measure_disk_usage_progress : NULL, task,
&result.disk_usage, &result.num_dirs, &result.num_files,
&error))
- g_task_return_pointer (task, g_memdup (&result, sizeof result), g_free);
+ g_task_return_pointer (task, g_memdup2 (&result, sizeof result), g_free);
else
g_task_return_error (task, error);
}
@@ -7776,7 +7777,7 @@ g_file_real_measure_disk_usage_async (GFile *file,
task = g_task_new (file, cancellable, callback, user_data);
g_task_set_source_tag (task, g_file_real_measure_disk_usage_async);
- g_task_set_task_data (task, g_memdup (&data, sizeof data), g_free);
+ g_task_set_task_data (task, g_memdup2 (&data, sizeof data), g_free);
g_task_set_priority (task, io_priority);
g_task_run_in_thread (task, measure_disk_usage_thread);
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index 17b7e3b01..499944395 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -20,6 +20,7 @@
#include "gsettingsschema-internal.h"
#include "gsettings.h"
+#include "gstrfuncsprivate.h"
#include "gvdb/gvdb-reader.h"
#include "strinfo.c"
@@ -1054,9 +1055,9 @@ g_settings_schema_list_children (GSettingsSchema *schema)
if (g_str_has_suffix (key, "/"))
{
- gint length = strlen (key);
+ gsize length = strlen (key);
- strv[j] = g_memdup (key, length);
+ strv[j] = g_memdup2 (key, length);
strv[j][length - 1] = '\0';
j++;
}
diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c
index c19fede4e..619fd48af 100644
--- a/gio/gwin32registrykey.c
+++ b/gio/gwin32registrykey.c
@@ -28,6 +28,8 @@
#include <ntstatus.h>
#include <winternl.h>
+#include "gstrfuncsprivate.h"
+
#ifndef _WDMDDK_
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
@@ -247,7 +249,7 @@ g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
new_iter->value_name_size = iter->value_name_size;
if (iter->value_data != NULL)
- new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size);
+ new_iter->value_data = g_memdup2 (iter->value_data, iter->value_data_size);
new_iter->value_data_size = iter->value_data_size;
@@ -268,8 +270,8 @@ g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize;
if (iter->value_data_expanded_u8 != NULL)
- new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8,
- iter->value_data_expanded_charsize);
+ new_iter->value_data_expanded_u8 = g_memdup2 (iter->value_data_expanded_u8,
+ iter->value_data_expanded_charsize);
new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize;
diff --git a/gio/tests/async-close-output-stream.c b/gio/tests/async-close-output-stream.c
index 5f6620275..d3f97a119 100644
--- a/gio/tests/async-close-output-stream.c
+++ b/gio/tests/async-close-output-stream.c
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <string.h>
+#include "gstrfuncsprivate.h"
+
#define DATA_TO_WRITE "Hello world\n"
typedef struct
@@ -147,9 +149,9 @@ prepare_data (SetupData *data,
data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream));
- g_assert_cmpint (data->expected_size, >, 0);
+ g_assert_cmpuint (data->expected_size, >, 0);
- data->expected_output = g_memdup (written, (guint)data->expected_size);
+ data->expected_output = g_memdup2 (written, data->expected_size);
/* then recreate the streams and prepare them for the asynchronous close */
destroy_streams (data);
diff --git a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c
index ef0dddeee..a3c842360 100644
--- a/gio/tests/gdbus-export.c
+++ b/gio/tests/gdbus-export.c
@@ -23,6 +23,7 @@
#include <string.h>
#include "gdbus-tests.h"
+#include "gstrfuncsprivate.h"
/* all tests rely on a shared mainloop */
static GMainLoop *loop = NULL;
@@ -652,7 +653,7 @@ subtree_introspect (GDBusConnection *connection,
g_assert_not_reached ();
}
- return g_memdup (interfaces, 2 * sizeof (void *));
+ return g_memdup2 (interfaces, 2 * sizeof (void *));
}
static const GDBusInterfaceVTable *
@@ -708,7 +709,7 @@ dynamic_subtree_introspect (GDBusConnection *connection,
{
const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL };
- return g_memdup (interfaces, 2 * sizeof (void *));
+ return g_memdup2 (interfaces, 2 * sizeof (void *));
}
static const GDBusInterfaceVTable *
diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c
index d5df16d91..f424d21cc 100644
--- a/gio/win32/gwinhttpfile.c
+++ b/gio/win32/gwinhttpfile.c
@@ -29,6 +29,7 @@
#include "gio/gfile.h"
#include "gio/gfileattribute.h"
#include "gio/gfileinfo.h"
+#include "gstrfuncsprivate.h"
#include "gwinhttpfile.h"
#include "gwinhttpfileinputstream.h"
#include "gwinhttpfileoutputstream.h"
@@ -393,10 +394,10 @@ g_winhttp_file_resolve_relative_path (GFile *file,
child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
child->vfs = winhttp_file->vfs;
child->url = winhttp_file->url;
- child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
- child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
- child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
- child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
+ child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
+ child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
+ child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
+ child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
child->url.lpszUrlPath = wnew_path;
child->url.dwUrlPathLength = wcslen (wnew_path);
child->url.lpszExtraInfo = NULL;
--
2.31.1
From 661f5edc901219a1a99bb51f171be13063878bd6 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Thu, 20 May 2021 15:58:53 -0500
Subject: [PATCH 6/6] gdatainputstream: replace easy use of g_memdup()
This code is passing a gsize, so might as well switch this to g_memdup2().
This is the only use of g_memdup() in GLib 2.56 that is not part of GLib
2.58. All other uses analyzed in glib!2000.
---
gio/gdatainputstream.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c
index 9f207b158..ebef7c797 100644
--- a/gio/gdatainputstream.c
+++ b/gio/gdatainputstream.c
@@ -27,6 +27,7 @@
#include "gioenumtypes.h"
#include "gioerror.h"
#include "glibintl.h"
+#include "gstrfuncsprivate.h"
#include <string.h>
@@ -1082,7 +1083,7 @@ g_data_input_stream_read_async (GDataInputStream *stream,
data = g_slice_new0 (GDataInputStreamReadData);
if (stop_chars_len == -1)
stop_chars_len = strlen (stop_chars);
- data->stop_chars = g_memdup (stop_chars, stop_chars_len);
+ data->stop_chars = g_memdup2 (stop_chars, stop_chars_len);
data->stop_chars_len = stop_chars_len;
data->last_saw_cr = FALSE;
--
2.31.1

@ -0,0 +1,388 @@
From 8fef6abe1131da0c8a7211c740a12ebe11cbcc51 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 10 Mar 2021 16:05:55 +0000
Subject: [PATCH 1/3] glocalfileoutputstream: Factor out a flag check
This clarifies the code a little. It introduces no functional changes.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
---
gio/glocalfileoutputstream.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 57d2d5dfe..6a70b2a04 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -751,6 +751,7 @@ handle_overwrite_open (const char *filename,
int res;
int mode;
int errsv;
+ gboolean replace_destination_set = (flags & G_FILE_CREATE_REPLACE_DESTINATION);
mode = mode_from_flags_or_info (flags, reference_info);
@@ -857,8 +858,8 @@ handle_overwrite_open (const char *filename,
* The second strategy consist simply in copying the old file
* to a backup file and rewrite the contents of the file.
*/
-
- if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
+
+ if (replace_destination_set ||
(!(original_stat.st_nlink > 1) && !is_symlink))
{
char *dirname, *tmp_filename;
@@ -877,7 +878,7 @@ handle_overwrite_open (const char *filename,
/* try to keep permissions (unless replacing) */
- if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
+ if (!replace_destination_set &&
(
#ifdef HAVE_FCHOWN
fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
@@ -1016,7 +1017,7 @@ handle_overwrite_open (const char *filename,
}
}
- if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
+ if (replace_destination_set)
{
g_close (fd, NULL);
--
2.31.1
From 6c10e8ce6905e8fcc3466eb8af707b5d0d3bdb85 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 24 Feb 2021 17:36:07 +0000
Subject: [PATCH 2/3] glocalfileoutputstream: Fix CREATE_REPLACE_DESTINATION
with symlinks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The `G_FILE_CREATE_REPLACE_DESTINATION` flag is equivalent to unlinking
the destination file and re-creating it from scratch. That did
previously work, but in the process the code would call `open(O_CREAT)`
on the file. If the file was a dangling symlink, this would create the
destination file (empty). Thats not an intended side-effect, and has
security implications if the symlink is controlled by a lower-privileged
process.
Fix that by not opening the destination file if its a symlink, and
adjusting the rest of the code to cope with
- the fact that `fd == -1` is not an error iff `is_symlink` is true,
- and that `original_stat` will contain the `lstat()` results for the
symlink now, rather than the `stat()` results for its target (again,
iff `is_symlink` is true).
This means that the target of the dangling symlink is no longer created,
which was the bug. The symlink itself continues to be replaced (as
before) with the new file — this is the intended behaviour of
`g_file_replace()`.
The behaviour for non-symlink cases, or cases where the symlink was not
dangling, should be unchanged.
Includes a unit test.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2325
---
gio/glocalfileoutputstream.c | 63 ++++++++++++++-------
gio/tests/file.c | 107 ++++++++++++++++++++++++++++++++++-
2 files changed, 149 insertions(+), 21 deletions(-)
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 6a70b2a04..4a7766f68 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -779,16 +779,22 @@ handle_overwrite_open (const char *filename,
/* Could be a symlink, or it could be a regular ELOOP error,
* but then the next open will fail too. */
is_symlink = TRUE;
- fd = g_open (filename, open_flags, mode);
+ if (!replace_destination_set)
+ fd = g_open (filename, open_flags, mode);
}
-#else
- fd = g_open (filename, open_flags, mode);
- errsv = errno;
+#else /* if !O_NOFOLLOW */
/* This is racy, but we do it as soon as possible to minimize the race */
is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
+
+ if (!is_symlink || !replace_destination_set)
+ {
+ fd = g_open (filename, open_flags, mode);
+ errsv = errno;
+ }
#endif
- if (fd == -1)
+ if (fd == -1 &&
+ (!is_symlink || !replace_destination_set))
{
char *display_name = g_filename_display_name (filename);
g_set_error (error, G_IO_ERROR,
@@ -800,10 +806,17 @@ handle_overwrite_open (const char *filename,
}
#ifdef G_OS_WIN32
- res = GLIB_PRIVATE_CALL (g_win32_fstat) (fd, &original_stat);
-#else
- res = fstat (fd, &original_stat);
+#error This patch has not been ported to Windows, sorry
#endif
+
+ if (!is_symlink)
+ {
+ res = fstat (fd, &original_stat);
+ }
+ else
+ {
+ res = lstat (filename, &original_stat);
+ }
errsv = errno;
if (res != 0)
@@ -821,16 +834,27 @@ handle_overwrite_open (const char *filename,
if (!S_ISREG (original_stat.st_mode))
{
if (S_ISDIR (original_stat.st_mode))
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_IS_DIRECTORY,
- _("Target file is a directory"));
- else
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_NOT_REGULAR_FILE,
- _("Target file is not a regular file"));
- goto err_out;
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_IS_DIRECTORY,
+ _("Target file is a directory"));
+ goto err_out;
+ }
+ else if (!is_symlink ||
+#ifdef S_ISLNK
+ !S_ISLNK (original_stat.st_mode)
+#else
+ FALSE
+#endif
+ )
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_REGULAR_FILE,
+ _("Target file is not a regular file"));
+ goto err_out;
+ }
}
if (etag != NULL)
@@ -911,7 +935,8 @@ handle_overwrite_open (const char *filename,
}
}
- g_close (fd, NULL);
+ if (fd >= 0)
+ g_close (fd, NULL);
*temp_filename = tmp_filename;
return tmpfd;
}
diff --git a/gio/tests/file.c b/gio/tests/file.c
index 98eeb85d4..44db6e295 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -671,8 +671,6 @@ test_replace_cancel (void)
guint count;
GError *error = NULL;
- g_test_bug ("629301");
-
path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
g_assert_no_error (error);
tmpdir = g_file_new_for_path (path);
@@ -779,6 +777,110 @@ test_replace_cancel (void)
g_object_unref (tmpdir);
}
+static void
+test_replace_symlink (void)
+{
+#ifdef G_OS_UNIX
+ gchar *tmpdir_path = NULL;
+ GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
+ GFileOutputStream *stream = NULL;
+ const gchar *new_contents = "this is a test message which should be written to source and not target";
+ gsize n_written;
+ GFileEnumerator *enumerator = NULL;
+ GFileInfo *info = NULL;
+ gchar *contents = NULL;
+ gsize length = 0;
+ GError *local_error = NULL;
+
+ /* Create a fresh, empty working directory. */
+ tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
+ g_assert_no_error (local_error);
+ tmpdir = g_file_new_for_path (tmpdir_path);
+
+ g_test_message ("Using temporary directory %s", tmpdir_path);
+ g_free (tmpdir_path);
+
+ /* Create symlink `source` which points to `target`. */
+ source_file = g_file_get_child (tmpdir, "source");
+ target_file = g_file_get_child (tmpdir, "target");
+ g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ /* Ensure that `target` doesnt exist */
+ g_assert_false (g_file_query_exists (target_file, NULL));
+
+ /* Replace the `source` symlink with a regular file using
+ * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
+ * following the symlink */
+ stream = g_file_replace (source_file, NULL, FALSE /* no backup */,
+ G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
+ &n_written, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_cmpint (n_written, ==, strlen (new_contents));
+
+ g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_clear_object (&stream);
+
+ /* At this point, there should still only be one file: `source`. It should
+ * now be a regular file. `target` should not exist. */
+ enumerator = g_file_enumerate_children (tmpdir,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_nonnull (info);
+
+ g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
+ g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
+
+ g_clear_object (&info);
+
+ info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_null (info);
+
+ g_file_enumerator_close (enumerator, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_clear_object (&enumerator);
+
+ /* Double-check that `target` doesnt exist */
+ g_assert_false (g_file_query_exists (target_file, NULL));
+
+ /* Check the content of `source`. */
+ g_file_load_contents (source_file,
+ NULL,
+ &contents,
+ &length,
+ NULL,
+ &local_error);
+ g_assert_no_error (local_error);
+ g_assert_cmpstr (contents, ==, new_contents);
+ g_assert_cmpuint (length, ==, strlen (new_contents));
+ g_free (contents);
+
+ /* Tidy up. */
+ g_file_delete (source_file, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_file_delete (tmpdir, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_clear_object (&target_file);
+ g_clear_object (&source_file);
+ g_clear_object (&tmpdir);
+#else /* if !G_OS_UNIX */
+ g_test_skip ("Symlink replacement tests can only be run on Unix")
+#endif
+}
+
static void
on_file_deleted (GObject *object,
GAsyncResult *result,
@@ -1170,6 +1272,7 @@ main (int argc, char *argv[])
g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
g_test_add_func ("/file/replace-load", test_replace_load);
g_test_add_func ("/file/replace-cancel", test_replace_cancel);
+ g_test_add_func ("/file/replace-symlink", test_replace_symlink);
g_test_add_func ("/file/async-delete", test_async_delete);
#ifdef G_OS_UNIX
g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
--
2.31.1
From 7f0b0d7fd744ad2f51236444005db49c80a0293d Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 24 Feb 2021 17:42:24 +0000
Subject: [PATCH 3/3] glocalfileoutputstream: Add a missing O_CLOEXEC flag to
replace()
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
---
gio/glocalfileoutputstream.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 4a7766f68..275770fa4 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -56,6 +56,12 @@
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#else
+#define HAVE_O_CLOEXEC 1
+#endif
+
struct _GLocalFileOutputStreamPrivate {
char *tmp_filename;
char *original_filename;
@@ -1127,7 +1133,7 @@ _g_local_file_output_stream_replace (const char *filename,
sync_on_close = FALSE;
/* If the file doesn't exist, create it */
- open_flags = O_CREAT | O_EXCL | O_BINARY;
+ open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC;
if (readable)
open_flags |= O_RDWR;
else
@@ -1157,8 +1163,11 @@ _g_local_file_output_stream_replace (const char *filename,
set_error_from_open_errno (filename, error);
return NULL;
}
-
-
+#if !defined(HAVE_O_CLOEXEC) && defined(F_SETFD)
+ else
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+#endif
+
stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
stream->priv->fd = fd;
stream->priv->sync_on_close = sync_on_close;
--
2.31.1

@ -0,0 +1,834 @@
From c5cc0bb6f2d6e468c7402915a0a4e6799f0febdf Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Fri, 7 Jun 2019 18:44:43 +0000
Subject: [PATCH 1/3] ghmac: Split off wrapper functions into ghmac-utils.c
Prep for adding a GnuTLS HMAC implementation; these are just
utility functions that call the "core" API.
---
glib/Makefile.am | 1 +
glib/ghmac-utils.c | 145 +++++++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 112 ----------------------------------
glib/meson.build | 1 +
4 files changed, 147 insertions(+), 112 deletions(-)
create mode 100644 glib/ghmac-utils.c
diff --git a/glib/Makefile.am b/glib/Makefile.am
index c0c3b92f0..43fa17051 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -126,6 +126,7 @@ libglib_2_0_la_SOURCES = \
ggettext.c \
ghash.c \
ghmac.c \
+ ghmac-utils.c \
ghook.c \
ghostutils.c \
giochannel.c \
diff --git a/glib/ghmac-utils.c b/glib/ghmac-utils.c
new file mode 100644
index 000000000..a17359ff1
--- /dev/null
+++ b/glib/ghmac-utils.c
@@ -0,0 +1,145 @@
+/* ghmac.h - data hashing functions
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "ghmac.h"
+
+#include "glib/galloca.h"
+#include "gatomic.h"
+#include "gslice.h"
+#include "gmem.h"
+#include "gstrfuncs.h"
+#include "gtestutils.h"
+#include "gtypes.h"
+#include "glibintl.h"
+
+/**
+ * g_compute_hmac_for_data:
+ * @digest_type: a #GChecksumType to use for the HMAC
+ * @key: (array length=key_len): the key to use in the HMAC
+ * @key_len: the length of the key
+ * @data: (array length=length): binary blob to compute the HMAC of
+ * @length: length of @data
+ *
+ * Computes the HMAC for a binary @data of @length. This is a
+ * convenience wrapper for g_hmac_new(), g_hmac_get_string()
+ * and g_hmac_unref().
+ *
+ * The hexadecimal string returned will be in lower case.
+ *
+ * Returns: the HMAC of the binary data as a string in hexadecimal.
+ * The returned string should be freed with g_free() when done using it.
+ *
+ * Since: 2.30
+ */
+gchar *
+g_compute_hmac_for_data (GChecksumType digest_type,
+ const guchar *key,
+ gsize key_len,
+ const guchar *data,
+ gsize length)
+{
+ GHmac *hmac;
+ gchar *retval;
+
+ g_return_val_if_fail (length == 0 || data != NULL, NULL);
+
+ hmac = g_hmac_new (digest_type, key, key_len);
+ if (!hmac)
+ return NULL;
+
+ g_hmac_update (hmac, data, length);
+ retval = g_strdup (g_hmac_get_string (hmac));
+ g_hmac_unref (hmac);
+
+ return retval;
+}
+
+/**
+ * g_compute_hmac_for_bytes:
+ * @digest_type: a #GChecksumType to use for the HMAC
+ * @key: the key to use in the HMAC
+ * @data: binary blob to compute the HMAC of
+ *
+ * Computes the HMAC for a binary @data. This is a
+ * convenience wrapper for g_hmac_new(), g_hmac_get_string()
+ * and g_hmac_unref().
+ *
+ * The hexadecimal string returned will be in lower case.
+ *
+ * Returns: the HMAC of the binary data as a string in hexadecimal.
+ * The returned string should be freed with g_free() when done using it.
+ *
+ * Since: 2.50
+ */
+gchar *
+g_compute_hmac_for_bytes (GChecksumType digest_type,
+ GBytes *key,
+ GBytes *data)
+{
+ gconstpointer byte_data;
+ gsize length;
+ gconstpointer key_data;
+ gsize key_len;
+
+ g_return_val_if_fail (data != NULL, NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ byte_data = g_bytes_get_data (data, &length);
+ key_data = g_bytes_get_data (key, &key_len);
+ return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length);
+}
+
+
+/**
+ * g_compute_hmac_for_string:
+ * @digest_type: a #GChecksumType to use for the HMAC
+ * @key: (array length=key_len): the key to use in the HMAC
+ * @key_len: the length of the key
+ * @str: the string to compute the HMAC for
+ * @length: the length of the string, or -1 if the string is nul-terminated
+ *
+ * Computes the HMAC for a string.
+ *
+ * The hexadecimal string returned will be in lower case.
+ *
+ * Returns: the HMAC as a hexadecimal string.
+ * The returned string should be freed with g_free()
+ * when done using it.
+ *
+ * Since: 2.30
+ */
+gchar *
+g_compute_hmac_for_string (GChecksumType digest_type,
+ const guchar *key,
+ gsize key_len,
+ const gchar *str,
+ gssize length)
+{
+ g_return_val_if_fail (length == 0 || str != NULL, NULL);
+
+ if (length < 0)
+ length = strlen (str);
+
+ return g_compute_hmac_for_data (digest_type, key, key_len,
+ (const guchar *) str, length);
+}
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 9b58fd81c..7db38e34a 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -329,115 +329,3 @@ g_hmac_get_digest (GHmac *hmac,
g_checksum_update (hmac->digesto, buffer, len);
g_checksum_get_digest (hmac->digesto, buffer, digest_len);
}
-
-/**
- * g_compute_hmac_for_data:
- * @digest_type: a #GChecksumType to use for the HMAC
- * @key: (array length=key_len): the key to use in the HMAC
- * @key_len: the length of the key
- * @data: (array length=length): binary blob to compute the HMAC of
- * @length: length of @data
- *
- * Computes the HMAC for a binary @data of @length. This is a
- * convenience wrapper for g_hmac_new(), g_hmac_get_string()
- * and g_hmac_unref().
- *
- * The hexadecimal string returned will be in lower case.
- *
- * Returns: the HMAC of the binary data as a string in hexadecimal.
- * The returned string should be freed with g_free() when done using it.
- *
- * Since: 2.30
- */
-gchar *
-g_compute_hmac_for_data (GChecksumType digest_type,
- const guchar *key,
- gsize key_len,
- const guchar *data,
- gsize length)
-{
- GHmac *hmac;
- gchar *retval;
-
- g_return_val_if_fail (length == 0 || data != NULL, NULL);
-
- hmac = g_hmac_new (digest_type, key, key_len);
- if (!hmac)
- return NULL;
-
- g_hmac_update (hmac, data, length);
- retval = g_strdup (g_hmac_get_string (hmac));
- g_hmac_unref (hmac);
-
- return retval;
-}
-
-/**
- * g_compute_hmac_for_bytes:
- * @digest_type: a #GChecksumType to use for the HMAC
- * @key: the key to use in the HMAC
- * @data: binary blob to compute the HMAC of
- *
- * Computes the HMAC for a binary @data. This is a
- * convenience wrapper for g_hmac_new(), g_hmac_get_string()
- * and g_hmac_unref().
- *
- * The hexadecimal string returned will be in lower case.
- *
- * Returns: the HMAC of the binary data as a string in hexadecimal.
- * The returned string should be freed with g_free() when done using it.
- *
- * Since: 2.50
- */
-gchar *
-g_compute_hmac_for_bytes (GChecksumType digest_type,
- GBytes *key,
- GBytes *data)
-{
- gconstpointer byte_data;
- gsize length;
- gconstpointer key_data;
- gsize key_len;
-
- g_return_val_if_fail (data != NULL, NULL);
- g_return_val_if_fail (key != NULL, NULL);
-
- byte_data = g_bytes_get_data (data, &length);
- key_data = g_bytes_get_data (key, &key_len);
- return g_compute_hmac_for_data (digest_type, key_data, key_len, byte_data, length);
-}
-
-
-/**
- * g_compute_hmac_for_string:
- * @digest_type: a #GChecksumType to use for the HMAC
- * @key: (array length=key_len): the key to use in the HMAC
- * @key_len: the length of the key
- * @str: the string to compute the HMAC for
- * @length: the length of the string, or -1 if the string is nul-terminated
- *
- * Computes the HMAC for a string.
- *
- * The hexadecimal string returned will be in lower case.
- *
- * Returns: the HMAC as a hexadecimal string.
- * The returned string should be freed with g_free()
- * when done using it.
- *
- * Since: 2.30
- */
-gchar *
-g_compute_hmac_for_string (GChecksumType digest_type,
- const guchar *key,
- gsize key_len,
- const gchar *str,
- gssize length)
-{
- g_return_val_if_fail (length == 0 || str != NULL, NULL);
-
- if (length < 0)
- length = strlen (str);
-
- return g_compute_hmac_for_data (digest_type, key, key_len,
- (const guchar *) str, length);
-}
diff --git a/glib/meson.build b/glib/meson.build
index c81e99f9c..306a67f13 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -138,6 +138,7 @@ glib_sources = files(
'ggettext.c',
'ghash.c',
'ghmac.c',
+ 'ghmac-utils.c',
'ghook.c',
'ghostutils.c',
'giochannel.c',
--
2.31.1
From 3befcf1eb31e0fa7a988b22a9c24240218cd4744 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Fri, 7 Jun 2019 19:36:54 +0000
Subject: [PATCH 2/3] Add a gnutls backend for GHmac
For RHEL we want apps to use FIPS-certified crypto libraries,
and HMAC apparently counts as "keyed" and hence needs to
be validated.
Bug: https://bugzilla.redhat.com/show_bug.cgi?id=1630260
Replaces: https://gitlab.gnome.org/GNOME/glib/merge_requests/897
This is a build-time option that backs the GHmac API with GnuTLS.
Most distributors ship glib-networking built with GnuTLS, and
most apps use glib-networking, so this isn't a net-new library
in most cases.
=======================================================================
mcatanzaro note:
I've updated Colin's original patch with several enhancements:
Implement g_hmac_copy() using gnutls_hmac_copy(), which didn't exist
when Colin developed this patch.
Removed use of GSlice
Better error checking in g_hmac_new(). It is possible for
gnutls_hmac_init() to fail if running in FIPS mode and an MD5 digest is
requested. In this case, we should return NULL rather than returning a
broken GHmac with a NULL gnutls_hmac_hd_t. This was leading to a later
null pointer dereference inside gnutls_hmac_update(). Applications are
responsible for checking to ensure the return value of g_hmac_new() is
not NULL since it is annotated as nullable. Added documentation to
indicate this possibility.
Properly handle length -1 in g_hmac_update(). This means we've been
given a NUL-terminated string and should use strlen(). GnuTLS doesn't
accept -1, so let's call strlen() ourselves.
Crash the application with g_error() if gnutls_hmac() fails for any
reason. This is necessary because g_hmac_update() is not fallible, so we
have no way to indicate error. Crashing seems better than returning the
wrong result later when g_hmac_get_string() or g_hmac_get_digest() is
later called. (Those functions are also not fallible.) Fortunately, I
don't think this error should actually be hit in practice.
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
---
glib/Makefile.am | 8 +-
glib/gchecksum.c | 9 +-
glib/gchecksumprivate.h | 32 +++++++
glib/ghmac-gnutls.c | 182 ++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 13 +++
glib/meson.build | 10 ++-
meson.build | 7 ++
meson_options.txt | 5 ++
8 files changed, 258 insertions(+), 8 deletions(-)
create mode 100644 glib/gchecksumprivate.h
create mode 100644 glib/ghmac-gnutls.c
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 43fa17051..1175bbe40 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -125,7 +125,7 @@ libglib_2_0_la_SOURCES = \
gfileutils.c \
ggettext.c \
ghash.c \
- ghmac.c \
+ ghmac-gnutls.c \
ghmac-utils.c \
ghook.c \
ghostutils.c \
@@ -352,11 +352,15 @@ pcre_lib = pcre/libpcre.la
pcre_inc =
endif
-libglib_2_0_la_CFLAGS = $(AM_CFLAGS) $(GLIB_HIDDEN_VISIBILITY_CFLAGS) $(LIBSYSTEMD_CFLAGS)
+gnutls_libs = $(shell pkg-config --libs gnutls)
+gnutls_cflags = $(shell pkg-config --cflags gnutls)
+
+libglib_2_0_la_CFLAGS = $(AM_CFLAGS) $(GLIB_HIDDEN_VISIBILITY_CFLAGS) $(LIBSYSTEMD_CFLAGS) $(gnutls_cflags)
libglib_2_0_la_LIBADD = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ @ICONV_LIBS@ @G_LIBS_EXTRA@ $(pcre_lib) $(G_THREAD_LIBS_EXTRA) $(G_THREAD_LIBS_FOR_GTHREAD) $(LIBSYSTEMD_LIBS)
libglib_2_0_la_DEPENDENCIES = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ $(glib_win32_res) $(glib_def)
libglib_2_0_la_LDFLAGS = $(GLIB_LINK_FLAGS) \
+ $(gnutls_libs) \
$(glib_win32_res_ldflag) \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic $(no_undefined)
diff --git a/glib/gchecksum.c b/glib/gchecksum.c
index 40b1d50e2..2f59d4a66 100644
--- a/glib/gchecksum.c
+++ b/glib/gchecksum.c
@@ -20,7 +20,7 @@
#include <string.h>
-#include "gchecksum.h"
+#include "gchecksumprivate.h"
#include "gslice.h"
#include "gmem.h"
@@ -173,9 +173,9 @@ sha_byte_reverse (guint32 *buffer,
}
#endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
-static gchar *
-digest_to_string (guint8 *digest,
- gsize digest_len)
+gchar *
+gchecksum_digest_to_string (guint8 *digest,
+ gsize digest_len)
{
gint len = digest_len * 2;
gint i;
@@ -195,6 +195,7 @@ digest_to_string (guint8 *digest,
return retval;
}
+#define digest_to_string gchecksum_digest_to_string
/*
* MD5 Checksum
diff --git a/glib/gchecksumprivate.h b/glib/gchecksumprivate.h
new file mode 100644
index 000000000..86c7a3b61
--- /dev/null
+++ b/glib/gchecksumprivate.h
@@ -0,0 +1,32 @@
+/* gstdioprivate.h - Private GLib stdio functions
+ *
+ * Copyright 2017 Руслан Ижбулатов
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_CHECKSUMPRIVATE_H__
+#define __G_CHECKSUMPRIVATE_H__
+
+#include "gchecksum.h"
+
+G_BEGIN_DECLS
+
+gchar *
+gchecksum_digest_to_string (guint8 *digest,
+ gsize digest_len);
+
+G_END_DECLS
+
+#endif
\ No newline at end of file
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
new file mode 100644
index 000000000..522b9b302
--- /dev/null
+++ b/glib/ghmac-gnutls.c
@@ -0,0 +1,182 @@
+/* ghmac.h - data hashing functions
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gnutls/crypto.h>
+
+#include "ghmac.h"
+
+#include "glib/galloca.h"
+#include "gatomic.h"
+#include "gslice.h"
+#include "gmem.h"
+#include "gstrfuncs.h"
+#include "gchecksumprivate.h"
+#include "gtestutils.h"
+#include "gtypes.h"
+#include "glibintl.h"
+
+struct _GHmac
+{
+ int ref_count;
+ GChecksumType digest_type;
+ gnutls_hmac_hd_t hmac;
+ gchar *digest_str;
+};
+
+GHmac *
+g_hmac_new (GChecksumType digest_type,
+ const guchar *key,
+ gsize key_len)
+{
+ gnutls_mac_algorithm_t algo;
+ GHmac *hmac = g_new0 (GHmac, 1);
+ int ret;
+
+ hmac->ref_count = 1;
+ hmac->digest_type = digest_type;
+
+ switch (digest_type)
+ {
+ case G_CHECKSUM_MD5:
+ algo = GNUTLS_MAC_MD5;
+ break;
+ case G_CHECKSUM_SHA1:
+ algo = GNUTLS_MAC_SHA1;
+ break;
+ case G_CHECKSUM_SHA256:
+ algo = GNUTLS_MAC_SHA256;
+ break;
+ case G_CHECKSUM_SHA384:
+ algo = GNUTLS_MAC_SHA384;
+ break;
+ case G_CHECKSUM_SHA512:
+ algo = GNUTLS_MAC_SHA512;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ ret = gnutls_hmac_init (&hmac->hmac, algo, key, key_len);
+ if (ret != 0)
+ {
+ /* There is no way to report an error here, but one possible cause of
+ * failure is that the requested digest may be disabled by FIPS mode.
+ */
+ g_free (hmac->hmac);
+ return NULL;
+ }
+
+ return hmac;
+}
+
+GHmac *
+g_hmac_copy (const GHmac *hmac)
+{
+ GHmac *copy;
+
+ g_return_val_if_fail (hmac != NULL, NULL);
+
+ copy = g_new0 (GHmac, 1);
+ copy->ref_count = 1;
+ copy->digest_type = hmac->digest_type;
+ copy->hmac = gnutls_hmac_copy (hmac->hmac);
+
+ /* g_hmac_copy is not allowed to fail, so we'll have to crash on error. */
+ if (!copy->hmac)
+ g_error ("gnutls_hmac_copy failed");
+
+ return copy;
+}
+
+GHmac *
+g_hmac_ref (GHmac *hmac)
+{
+ g_return_val_if_fail (hmac != NULL, NULL);
+
+ g_atomic_int_inc (&hmac->ref_count);
+
+ return hmac;
+}
+
+void
+g_hmac_unref (GHmac *hmac)
+{
+ g_return_if_fail (hmac != NULL);
+
+ if (g_atomic_int_dec_and_test (&hmac->ref_count))
+ {
+ gnutls_hmac_deinit (hmac->hmac, NULL);
+ g_free (hmac->digest_str);
+ g_free (hmac);
+ }
+}
+
+
+void
+g_hmac_update (GHmac *hmac,
+ const guchar *data,
+ gssize length)
+{
+ int ret;
+
+ g_return_if_fail (hmac != NULL);
+ g_return_if_fail (length == 0 || data != NULL);
+
+ if (length == -1)
+ length = strlen ((const char *)data);
+
+ /* g_hmac_update is not allowed to fail, so we'll have to crash on error. */
+ ret = gnutls_hmac (hmac->hmac, data, length);
+ if (ret != 0)
+ g_error ("gnutls_hmac failed: %s", gnutls_strerror (ret));
+}
+
+const gchar *
+g_hmac_get_string (GHmac *hmac)
+{
+ guint8 *buffer;
+ gsize digest_len;
+
+ g_return_val_if_fail (hmac != NULL, NULL);
+
+ if (hmac->digest_str)
+ return hmac->digest_str;
+
+ digest_len = g_checksum_type_get_length (hmac->digest_type);
+ buffer = g_alloca (digest_len);
+
+ gnutls_hmac_output (hmac->hmac, buffer);
+ hmac->digest_str = gchecksum_digest_to_string (buffer, digest_len);
+ return hmac->digest_str;
+}
+
+
+void
+g_hmac_get_digest (GHmac *hmac,
+ guint8 *buffer,
+ gsize *digest_len)
+{
+ g_return_if_fail (hmac != NULL);
+
+ gnutls_hmac_output (hmac->hmac, buffer);
+ *digest_len = g_checksum_type_get_length (hmac->digest_type);
+}
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 7db38e34a..b03a5aea7 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -33,6 +33,7 @@
#include "gtypes.h"
#include "glibintl.h"
+#error "build configuration error"
/**
* SECTION:hmac
@@ -84,6 +85,18 @@ struct _GHmac
* Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
* Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
*
+ * Note that #GHmac creation may fail, in which case this function will
+ * return %NULL. Since there is no error parameter, it is not possible
+ * to indicate why.
+ *
+ * In Fedora, CentOS Stream, and Red Hat Enterprise Linux, GLib is
+ * configured to use GnuTLS to implement #GHmac in order to support FIPS
+ * compliance. This introduces additional failure possibilities that are
+ * not present in upstream GLib. For example, the creation of a #GHmac
+ * will fail if @digest_type is %G_CHECKSUM_MD5 and the system is
+ * running in FIPS mode. #GHmac creation may also fail if GLib is unable
+ * to load GnuTLS.
+ *
* Returns: the newly created #GHmac, or %NULL.
* Use g_hmac_unref() to free the memory allocated by it.
*
diff --git a/glib/meson.build b/glib/meson.build
index 306a67f13..07d41456d 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -127,6 +127,7 @@ glib_sources = files(
'gbytes.c',
'gcharset.c',
'gchecksum.c',
+ 'gchecksumprivate.h',
'gconvert.c',
'gdataset.c',
'gdate.c',
@@ -137,7 +138,6 @@ glib_sources = files(
'gfileutils.c',
'ggettext.c',
'ghash.c',
- 'ghmac.c',
'ghmac-utils.c',
'ghook.c',
'ghostutils.c',
@@ -223,6 +223,12 @@ else
glib_dtrace_hdr = []
endif
+if get_option('gnutls')
+ glib_sources += files('ghmac-gnutls.c')
+else
+ glib_sources += files('ghmac.c')
+endif
+
pcre_static_args = []
if use_pcre_static_flag
@@ -239,7 +245,7 @@ libglib = library('glib-2.0',
link_args : platform_ldflags + noseh_link_args,
include_directories : configinc,
link_with : [charset_lib, gnulib_lib],
- dependencies : [pcre, thread_dep, libintl, librt] + libiconv + platform_deps,
+ dependencies : [pcre, thread_dep, libintl, librt] + libgnutls_dep + libiconv + platform_deps,
c_args : ['-DG_LOG_DOMAIN="GLib"', '-DGLIB_COMPILATION'] + pcre_static_args + glib_hidden_visibility_args
)
diff --git a/meson.build b/meson.build
index 0cefee51d..eaf8d3900 100644
--- a/meson.build
+++ b/meson.build
@@ -1596,6 +1596,13 @@ if host_system == 'linux' and get_option('libmount')
libmount_dep = [dependency('mount', version : '>=2.23', required : true)]
endif
+# gnutls is used optionally by ghmac
+libgnutls_dep = []
+if get_option('gnutls')
+ libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
+ glib_conf.set('HAVE_GNUTLS', 1)
+endif
+
if host_system == 'windows'
winsock2 = cc.find_library('ws2_32')
endif
diff --git a/meson_options.txt b/meson_options.txt
index 4504c6858..d18c42a36 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -34,6 +34,11 @@ option('libmount',
value : true,
description : 'build with libmount support')
+option('gnutls',
+ type : 'boolean',
+ value : false,
+ description : 'build with gnutls support')
+
option('internal_pcre',
type : 'boolean',
value : false,
--
2.31.1
From 87280b23902290dcf843a42d06cedeef571a673f Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Thu, 1 Jul 2021 15:51:26 -0500
Subject: [PATCH 3/3] Add more tests for GHmac
This will test a few problems that we hit recently:
g_hmac_copy() is broken, https://bugzilla.redhat.com/show_bug.cgi?id=1786538
Crash in g_hmac_update() in FIPS mode, https://bugzilla.redhat.com/show_bug.cgi?id=1971533
Crash when passing -1 length to g_hmac_update() (discovered in #1971533)
---
glib/tests/hmac.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/glib/tests/hmac.c b/glib/tests/hmac.c
index 3ac3206df..16b2fac9c 100644
--- a/glib/tests/hmac.c
+++ b/glib/tests/hmac.c
@@ -493,6 +493,27 @@ test_hmac_for_bytes (void)
g_bytes_unref (data);
}
+static void
+test_ghmac_gnutls_regressions (void)
+{
+ GHmac *hmac;
+ GHmac *copy;
+
+ hmac = g_hmac_new (G_CHECKSUM_SHA256, (const guchar *)"abc123", sizeof ("abc123"));
+ g_assert_nonnull (hmac);
+
+ /* Ensure g_hmac_update() does not crash when called with -1. */
+ g_hmac_update (hmac, (const guchar *)"You win again, gravity!", -1);
+
+ /* Ensure g_hmac_copy() does not crash. */
+ copy = g_hmac_copy (hmac);
+ g_assert_nonnull (hmac);
+ g_hmac_unref (hmac);
+
+ g_assert_cmpstr (g_hmac_get_string (copy), ==, "795ba6900bcb22e8ce65c2ec02db4e85697da921deb960ee3143bf88a4a60f83");
+ g_hmac_unref (copy);
+}
+
int
main (int argc,
char **argv)
@@ -545,6 +566,7 @@ main (int argc,
g_test_add_func ("/hmac/for-data", test_hmac_for_data);
g_test_add_func ("/hmac/for-string", test_hmac_for_string);
g_test_add_func ("/hmac/for-bytes", test_hmac_for_bytes);
+ g_test_add_func ("/hmac/ghmac-gnutls-regressions", test_ghmac_gnutls_regressions);
return g_test_run ();
}
--
2.31.1

@ -0,0 +1,386 @@
From 2bad3cb3bf8f0cc3f45057061f9a538ecf7742b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Thu, 14 Feb 2019 17:46:33 +0200
Subject: [PATCH 1/5] Use atomic reference counting for GSource
If attached to a context already it would use a mutex instead but at
least before that the reference counting is not thread-safe currently.
---
glib/gmain.c | 50 +++++++++++++++-----------------------------------
1 file changed, 15 insertions(+), 35 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 26e68823d..5b91c3117 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -374,15 +374,6 @@ typedef struct _GSourceIter
#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
#define SOURCE_BLOCKED(source) (((source)->flags & G_SOURCE_BLOCKED) != 0)
-#define SOURCE_UNREF(source, context) \
- G_STMT_START { \
- if ((source)->ref_count > 1) \
- (source)->ref_count--; \
- else \
- g_source_unref_internal ((source), (context), TRUE); \
- } G_STMT_END
-
-
/* Forward declarations */
static void g_source_unref_internal (GSource *source,
@@ -977,10 +968,10 @@ g_source_iter_next (GSourceIter *iter, GSource **source)
*/
if (iter->source && iter->may_modify)
- SOURCE_UNREF (iter->source, iter->context);
+ g_source_unref_internal (iter->source, iter->context, TRUE);
iter->source = next_source;
if (iter->source && iter->may_modify)
- iter->source->ref_count++;
+ g_source_ref (iter->source);
*source = iter->source;
return *source != NULL;
@@ -994,7 +985,7 @@ g_source_iter_clear (GSourceIter *iter)
{
if (iter->source && iter->may_modify)
{
- SOURCE_UNREF (iter->source, iter->context);
+ g_source_unref_internal (iter->source, iter->context, TRUE);
iter->source = NULL;
}
}
@@ -1135,7 +1126,7 @@ g_source_attach_unlocked (GSource *source,
source->context = context;
source->source_id = id;
- source->ref_count++;
+ g_source_ref (source);
g_hash_table_insert (context->sources, GUINT_TO_POINTER (id), source);
@@ -1675,7 +1666,7 @@ g_source_set_funcs (GSource *source,
{
g_return_if_fail (source != NULL);
g_return_if_fail (source->context == NULL);
- g_return_if_fail (source->ref_count > 0);
+ g_return_if_fail (g_atomic_int_get (&source->ref_count) > 0);
g_return_if_fail (funcs != NULL);
source->source_funcs = funcs;
@@ -2050,19 +2041,9 @@ g_source_set_name_by_id (guint tag,
GSource *
g_source_ref (GSource *source)
{
- GMainContext *context;
-
g_return_val_if_fail (source != NULL, NULL);
- context = source->context;
-
- if (context)
- LOCK_CONTEXT (context);
-
- source->ref_count++;
-
- if (context)
- UNLOCK_CONTEXT (context);
+ g_atomic_int_inc (&source->ref_count);
return source;
}
@@ -2078,12 +2059,11 @@ g_source_unref_internal (GSource *source,
GSourceCallbackFuncs *old_cb_funcs = NULL;
g_return_if_fail (source != NULL);
-
+
if (!have_lock && context)
LOCK_CONTEXT (context);
- source->ref_count--;
- if (source->ref_count == 0)
+ if (g_atomic_int_dec_and_test (&source->ref_count))
{
TRACE (GLIB_SOURCE_BEFORE_FREE (source, context,
source->source_funcs->finalize));
@@ -2107,20 +2087,20 @@ g_source_unref_internal (GSource *source,
{
/* Temporarily increase the ref count again so that GSource methods
* can be called from finalize(). */
- source->ref_count++;
+ g_atomic_int_inc (&source->ref_count);
if (context)
UNLOCK_CONTEXT (context);
source->source_funcs->finalize (source);
if (context)
LOCK_CONTEXT (context);
- source->ref_count--;
+ g_atomic_int_add (&source->ref_count, -1);
}
if (old_cb_funcs)
{
/* Temporarily increase the ref count again so that GSource methods
* can be called from callback_funcs.unref(). */
- source->ref_count++;
+ g_atomic_int_inc (&source->ref_count);
if (context)
UNLOCK_CONTEXT (context);
@@ -2128,7 +2108,7 @@ g_source_unref_internal (GSource *source,
if (context)
LOCK_CONTEXT (context);
- source->ref_count--;
+ g_atomic_int_add (&source->ref_count, -1);
}
g_free (source->name);
@@ -3201,7 +3181,7 @@ g_main_dispatch (GMainContext *context)
}
}
- SOURCE_UNREF (source, context);
+ g_source_unref_internal (source, context, TRUE);
}
g_ptr_array_set_size (context->pending_dispatches, 0);
@@ -3440,7 +3420,7 @@ g_main_context_prepare (GMainContext *context,
for (i = 0; i < context->pending_dispatches->len; i++)
{
if (context->pending_dispatches->pdata[i])
- SOURCE_UNREF ((GSource *)context->pending_dispatches->pdata[i], context);
+ g_source_unref_internal ((GSource *)context->pending_dispatches->pdata[i], context, TRUE);
}
g_ptr_array_set_size (context->pending_dispatches, 0);
@@ -3788,7 +3768,7 @@ g_main_context_check (GMainContext *context,
if (source->flags & G_SOURCE_READY)
{
- source->ref_count++;
+ g_source_ref (source);
g_ptr_array_add (context->pending_dispatches, source);
n_ready++;
--
2.31.1
From 323d0c7658a9a44efc327840c0667044a4b98f89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Mon, 3 Feb 2020 15:38:28 +0200
Subject: [PATCH 2/5] GMainContext - Fix GSource iterator if iteration can
modify the list
We first have to ref the next source and then unref the previous one.
This might be the last reference to the previous source, and freeing the
previous source might unref and free the next one which would then leave
use with a dangling pointer here.
Fixes https://gitlab.gnome.org/GNOME/glib/issues/2031
---
glib/gmain.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 5b91c3117..a3ea1d36c 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -965,13 +965,17 @@ g_source_iter_next (GSourceIter *iter, GSource **source)
* GSourceList to be removed from source_lists (if iter->source is
* the only source in its list, and it is destroyed), so we have to
* keep it reffed until after we advance iter->current_list, above.
+ *
+ * Also we first have to ref the next source before unreffing the
+ * previous one as unreffing the previous source can potentially
+ * free the next one.
*/
+ if (next_source && iter->may_modify)
+ g_source_ref (next_source);
if (iter->source && iter->may_modify)
g_source_unref_internal (iter->source, iter->context, TRUE);
iter->source = next_source;
- if (iter->source && iter->may_modify)
- g_source_ref (iter->source);
*source = iter->source;
return *source != NULL;
--
2.31.1
From fc051ec83d8894dd754bf364562ba9be9ff999fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Mon, 3 Feb 2020 15:35:51 +0200
Subject: [PATCH 3/5] GMainContext - Fix memory leaks and memory corruption
when freeing sources while freeing a context
Instead of destroying sources directly while freeing the context, and
potentially freeing them if this was the last reference to them, collect
new references of all sources in a separate list before and at the same
time invalidate their context so that they can't access it anymore. Only
once all sources have their context invalidated, destroy them while
still keeping a reference to them. Once all sources are destroyed we get
rid of the additional references and free them if nothing else keeps a
reference to them anymore.
This fixes a regression introduced by 26056558be in 2012.
The previous code that invalidated the context of each source and then
destroyed it before going to the next source without keeping an
additional reference caused memory leaks or memory corruption depending
on the order of the sources in the sources lists.
If a source was destroyed it might happen that this was the last
reference to this source, and it would then be freed. This would cause
the finalize function to be called, which might destroy and unref
another source and potentially free it. This other source would then
either
- go through the normal free logic and change the intern linked list
between the sources, while other sources that are unreffed as part of
the main context freeing would not. As such the list would be in an
inconsistent state and we might dereference freed memory.
- go through the normal destroy and free logic but because the context
pointer was already invalidated it would simply mark the source as
destroyed without actually removing it from the context. This would
then cause a memory leak because the reference owned by the context is
not freed.
Fixes https://github.com/gtk-rs/glib/issues/583 while still keeping
https://bugzilla.gnome.org/show_bug.cgi?id=661767 fixes.
---
glib/gmain.c | 35 ++++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index a3ea1d36c..1c249ad02 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -534,6 +534,7 @@ g_main_context_unref (GMainContext *context)
GSourceIter iter;
GSource *source;
GList *sl_iter;
+ GSList *s_iter, *remaining_sources = NULL;
GSourceList *list;
guint i;
@@ -553,10 +554,30 @@ g_main_context_unref (GMainContext *context)
/* g_source_iter_next() assumes the context is locked. */
LOCK_CONTEXT (context);
- g_source_iter_init (&iter, context, TRUE);
+
+ /* First collect all remaining sources from the sources lists and store a
+ * new reference in a separate list. Also set the context of the sources
+ * to NULL so that they can't access a partially destroyed context anymore.
+ *
+ * We have to do this first so that we have a strong reference to all
+ * sources and destroying them below does not also free them, and so that
+ * none of the sources can access the context from their finalize/dispose
+ * functions. */
+ g_source_iter_init (&iter, context, FALSE);
while (g_source_iter_next (&iter, &source))
{
source->context = NULL;
+ remaining_sources = g_slist_prepend (remaining_sources, g_source_ref (source));
+ }
+ g_source_iter_clear (&iter);
+
+ /* Next destroy all sources. As we still hold a reference to all of them,
+ * this won't cause any of them to be freed yet and especially prevents any
+ * source that unrefs another source from its finalize function to be freed.
+ */
+ for (s_iter = remaining_sources; s_iter; s_iter = s_iter->next)
+ {
+ source = s_iter->data;
g_source_destroy_internal (source, context, TRUE);
}
UNLOCK_CONTEXT (context);
@@ -581,6 +602,18 @@ g_main_context_unref (GMainContext *context)
g_cond_clear (&context->cond);
g_free (context);
+
+ /* And now finally get rid of our references to the sources. This will cause
+ * them to be freed unless something else still has a reference to them. Due
+ * to setting the context pointers in the sources to NULL above, this won't
+ * ever access the context or the internal linked list inside the GSource.
+ * We already removed the sources completely from the context above. */
+ for (s_iter = remaining_sources; s_iter; s_iter = s_iter->next)
+ {
+ source = s_iter->data;
+ g_source_unref_internal (source, NULL, FALSE);
+ }
+ g_slist_free (remaining_sources);
}
/* Helper function used by mainloop/overflow test.
--
2.31.1
From 1d16e92028f235ed9cd786070832d5bd71017661 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Tue, 11 Feb 2020 09:34:38 +0200
Subject: [PATCH 4/5] GMainContext - Move mutex unlocking in destructor right
before freeing the mutex
This does not have any behaviour changes but is cleaner. The mutex is
only unlocked now after all operations on the context are done and right
before freeing the mutex and the context itself.
---
glib/gmain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 1c249ad02..44e6ed0c3 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -580,7 +580,6 @@ g_main_context_unref (GMainContext *context)
source = s_iter->data;
g_source_destroy_internal (source, context, TRUE);
}
- UNLOCK_CONTEXT (context);
for (sl_iter = context->source_lists; sl_iter; sl_iter = sl_iter->next)
{
@@ -591,6 +590,7 @@ g_main_context_unref (GMainContext *context)
g_hash_table_destroy (context->sources);
+ UNLOCK_CONTEXT (context);
g_mutex_clear (&context->mutex);
g_ptr_array_free (context->pending_dispatches, TRUE);
--
2.31.1
From 02ad7294ad5895178df73a6cd8546c6e67097493 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Tue, 13 Oct 2020 15:09:43 +0200
Subject: [PATCH 5/5] gmain: Fix possible locking issue in source unref
When unref'ing child sources, the lock is already held. But instead of
passing TRUE to g_source_unref_internal it currently passes whether the
lock was already held outside of the current invocation. Just pass TRUE
to fix this possible issue.
---
glib/gmain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 44e6ed0c3..95992253d 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -2164,7 +2164,7 @@ g_source_unref_internal (GSource *source,
g_slist_remove (source->priv->child_sources, child_source);
child_source->priv->parent_source = NULL;
- g_source_unref_internal (child_source, context, have_lock);
+ g_source_unref_internal (child_source, context, TRUE);
}
g_slice_free (GSourcePrivate, source->priv);
--
2.31.1

@ -0,0 +1,431 @@
From c48c984d39afeae84b0cad515f08f83c711fd9c4 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Thu, 13 Sep 2018 10:25:05 +0100
Subject: [PATCH 1/9] gnetworkmonitornm: Set a GError properly on an error
handling path
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
All the other initialisation failure paths set a GError, but this one
didnt. Set a GError to avoid breaking the invariant that returning
FALSE should always have a GError set.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://gitlab.gnome.org/GNOME/glib/issues/1523
---
gio/gnetworkmonitornm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 20a86571f..5bc8c925a 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -309,6 +309,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
if (!name_owner)
{
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("NetworkManager not running"));
g_object_unref (proxy);
return FALSE;
}
--
2.33.1
From d139986b1f213a7e1c1e3968ad2d8270f820bd57 Mon Sep 17 00:00:00 2001
From: Antonio Larrosa <alarrosa@suse.com>
Date: Tue, 12 Mar 2019 18:35:10 +0100
Subject: [PATCH 2/9] Handle an UNKNOWN NetworkManager connectivity as NONE
nm_conn_to_g_conn already handles UNKNOWN like NONE (returning
G_NETWORK_CONNECTIVITY_LOCAL in both cases). So in sync_properties
we should also set new_connectivity to G_NETWORK_CONNECTIVITY_LOCAL
for both NM_CONNECTIVITY_UNKNOWN and NM_CONNECTIVITY_NONE.
This has the added benefit that when NetworkManager returns the network
connectivity is UNKNOWN, we set network_available to FALSE as it should
be. Previously, there were cases in a laptop with no network access,
that g_network_monitor_get_network_available returned true, which was
wrong and is also fixed with this commit.
---
gio/gnetworkmonitornm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 5bc8c925a..4e2a35e8a 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -167,7 +167,8 @@ sync_properties (GNetworkMonitorNM *nm,
nm_connectivity = g_variant_get_uint32 (v);
g_variant_unref (v);
- if (nm_connectivity == NM_CONNECTIVITY_NONE)
+ if (nm_connectivity == NM_CONNECTIVITY_UNKNOWN ||
+ nm_connectivity == NM_CONNECTIVITY_NONE)
{
new_network_available = FALSE;
new_network_metered = FALSE;
--
2.33.1
From 5b4e6f9813cf90c690d8974635b0aeff8f5d2c5d Mon Sep 17 00:00:00 2001
From: Fabrice Bellet <fabrice@bellet.info>
Date: Mon, 29 Apr 2019 12:05:54 +0000
Subject: [PATCH 3/9] gnetworkmonitornm: Fix network available detection
The network-available property can be asserted by querying the NMState
describing the current overval network state, instead of the
NMConnectivityState. The advantage of the NMState is that is reflects
immediately the network state modification, while the connectivity
state is tested at a fixed frequency.
---
gio/gnetworkmonitornm.c | 39 ++++++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 4e2a35e8a..7bb480f54 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -52,6 +52,19 @@ typedef enum {
NM_CONNECTIVITY_FULL
} NMConnectivityState;
+/* Copied from https://developer.gnome.org/libnm-util/stable/libnm-util-NetworkManager.html#NMState;
+ * used inline to avoid a NetworkManager dependency from GLib. */
+typedef enum {
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP = 10,
+ NM_STATE_DISCONNECTED = 20,
+ NM_STATE_DISCONNECTING = 30,
+ NM_STATE_CONNECTING = 40,
+ NM_STATE_CONNECTED_LOCAL = 50,
+ NM_STATE_CONNECTED_SITE = 60,
+ NM_STATE_CONNECTED_GLOBAL = 70,
+} NMState;
+
struct _GNetworkMonitorNMPrivate
{
GDBusProxy *proxy;
@@ -155,11 +168,19 @@ sync_properties (GNetworkMonitorNM *nm,
gboolean emit_signals)
{
GVariant *v;
+ NMState nm_state;
NMConnectivityState nm_connectivity;
gboolean new_network_available;
gboolean new_network_metered;
GNetworkConnectivity new_connectivity;
+ v = g_dbus_proxy_get_cached_property (nm->priv->proxy, "State");
+ if (!v)
+ return;
+
+ nm_state = g_variant_get_uint32 (v);
+ g_variant_unref (v);
+
v = g_dbus_proxy_get_cached_property (nm->priv->proxy, "Connectivity");
if (!v)
return;
@@ -167,14 +188,26 @@ sync_properties (GNetworkMonitorNM *nm,
nm_connectivity = g_variant_get_uint32 (v);
g_variant_unref (v);
- if (nm_connectivity == NM_CONNECTIVITY_UNKNOWN ||
- nm_connectivity == NM_CONNECTIVITY_NONE)
+ if (nm_state <= NM_STATE_CONNECTED_LOCAL)
{
new_network_available = FALSE;
new_network_metered = FALSE;
new_connectivity = G_NETWORK_CONNECTIVITY_LOCAL;
}
- else
+ else if (nm_state <= NM_STATE_CONNECTED_SITE)
+ {
+ new_network_available = FALSE;
+ new_network_metered = FALSE;
+ if (nm_connectivity == NM_CONNECTIVITY_PORTAL)
+ {
+ new_connectivity = G_NETWORK_CONNECTIVITY_PORTAL;
+ }
+ else
+ {
+ new_connectivity = G_NETWORK_CONNECTIVITY_LIMITED;
+ }
+ }
+ else /* nm_state == NM_STATE_CONNECTED_FULL */
{
/* this is only available post NM 1.0 */
--
2.33.1
From 96fba295771d600e4f0f522400b2fb9b1ff42cee Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 31 May 2019 11:19:07 +0100
Subject: [PATCH 4/9] gnetworkmonitornm: Consider NM_STATE_CONNECTED_SITE to be
available
`NM_STATE_CONNECTED_SITE` is documented to mean that a default route is
available, but that the internet connectivity check failed. A default
route being available is compatible with the documentation for
GNetworkMonitor:network-available, which should be true if the system
has a default route for at least one of IPv4 and IPv6.
https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1788
---
gio/gnetworkmonitornm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 7bb480f54..9013fd49c 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -196,7 +196,7 @@ sync_properties (GNetworkMonitorNM *nm,
}
else if (nm_state <= NM_STATE_CONNECTED_SITE)
{
- new_network_available = FALSE;
+ new_network_available = TRUE;
new_network_metered = FALSE;
if (nm_connectivity == NM_CONNECTIVITY_PORTAL)
{
--
2.33.1
From 74e5f472c838115f0ba19ac501805cb5b2ca837f Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 29 Jul 2019 17:25:21 +0200
Subject: [PATCH 5/9] gnetworkmonitornm: Disconnect g-signal from proxy
So that we're sure never to receive a signal if something is keeping the
proxy alive.
---
gio/gnetworkmonitornm.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 9013fd49c..52073fac9 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -68,6 +68,7 @@ typedef enum {
struct _GNetworkMonitorNMPrivate
{
GDBusProxy *proxy;
+ guint signal_id;
GNetworkConnectivity connectivity;
gboolean network_available;
@@ -360,8 +361,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
return FALSE;
}
- g_signal_connect (G_OBJECT (proxy), "g-signal",
- G_CALLBACK (proxy_signal_cb), nm);
+ nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
+ G_CALLBACK (proxy_signal_cb), nm);
nm->priv->proxy = proxy;
sync_properties (nm, FALSE);
@@ -373,6 +374,13 @@ g_network_monitor_nm_finalize (GObject *object)
{
GNetworkMonitorNM *nm = G_NETWORK_MONITOR_NM (object);
+ if (nm->priv->proxy != NULL &&
+ nm->priv->signal_id != 0)
+ {
+ g_signal_handler_disconnect (nm->priv->proxy,
+ nm->priv->signal_id);
+ nm->priv->signal_id = 0;
+ }
g_clear_object (&nm->priv->proxy);
G_OBJECT_CLASS (g_network_monitor_nm_parent_class)->finalize (object);
--
2.33.1
From eeaf1de6e695afd971d67137caa8e39e1c1267df Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 29 Jul 2019 17:26:20 +0200
Subject: [PATCH 6/9] gnetworkmonitornm: Arguments to g-signal's callback are
const
---
gio/gnetworkmonitornm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 52073fac9..479653a51 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -268,8 +268,8 @@ update_cached_property (GDBusProxy *proxy,
static void
proxy_signal_cb (GDBusProxy *proxy,
- gchar *sender_name,
- gchar *signal_name,
+ const gchar *sender_name,
+ const gchar *signal_name,
GVariant *parameters,
GNetworkMonitorNM *nm)
{
--
2.33.1
From 46d70700c85e4419942c8a3d08bd0bf842702c4a Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 29 Jul 2019 17:26:47 +0200
Subject: [PATCH 7/9] gnetworkmonitornm: Remove double-space
---
gio/gnetworkmonitornm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 479653a51..5a36a0ba1 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -391,7 +391,7 @@ g_network_monitor_nm_class_init (GNetworkMonitorNMClass *nl_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
- gobject_class->finalize = g_network_monitor_nm_finalize;
+ gobject_class->finalize = g_network_monitor_nm_finalize;
gobject_class->get_property = g_network_monitor_nm_get_property;
g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
--
2.33.1
From 72291aac3dac7a8ed4c85eb41608f3f5f9ad7681 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 12 Oct 2021 12:01:50 +0200
Subject: [PATCH 8/9] gnetworkmonitornm: Stop using removed PropertiesChanged
signal
Use the org.freedesktop.DBus.Properties interface to listen
to PropertiesChanged signals on /org/freedesktop/NetworkManager.
NetworkManager used to provide its own legacy PropertiesChanged
signal, but that was dropped in
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/853
This requires NetworkManager >= 1.2 (2016)
Fixes: #2505
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1946196
---
gio/gnetworkmonitornm.c | 29 +++++++----------------------
1 file changed, 7 insertions(+), 22 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 5a36a0ba1..6a6d1d666 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -267,29 +267,14 @@ update_cached_property (GDBusProxy *proxy,
}
static void
-proxy_signal_cb (GDBusProxy *proxy,
- const gchar *sender_name,
- const gchar *signal_name,
- GVariant *parameters,
- GNetworkMonitorNM *nm)
+proxy_properties_changed_cb (GDBusProxy *proxy,
+ GVariant *changed_properties,
+ GStrv invalidated_properties,
+ GNetworkMonitorNM *nm)
{
- GVariant *asv;
GVariantDict *dict;
- if (g_strcmp0 (signal_name, "PropertiesChanged") != 0)
- return;
-
- g_variant_get (parameters, "(@a{sv})", &asv);
- if (!asv)
- return;
-
- dict = g_variant_dict_new (asv);
- g_variant_unref (asv);
- if (!dict)
- {
- g_warning ("Failed to handle PropertiesChanged signal from NetworkManager");
- return;
- }
+ dict = g_variant_dict_new (changed_properties);
update_cached_property (nm->priv->proxy, "Connectivity", dict);
@@ -361,8 +346,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
return FALSE;
}
- nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
- G_CALLBACK (proxy_signal_cb), nm);
+ nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-properties-changed",
+ G_CALLBACK (proxy_properties_changed_cb), nm);
nm->priv->proxy = proxy;
sync_properties (nm, FALSE);
--
2.33.1
From 3bafff71d7588285763f603b23c830722a2169d1 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 12 Oct 2021 17:31:42 +0200
Subject: [PATCH 9/9] gnetworkmonitornm: Do not re-update cached property
GDBusProxy already takes care of updating the cached property
before emitting the signal, so there is no need to do this
a second time ourselves.
---
gio/gnetworkmonitornm.c | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 6a6d1d666..a8040fb36 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -252,34 +252,12 @@ sync_properties (GNetworkMonitorNM *nm,
}
}
-static void
-update_cached_property (GDBusProxy *proxy,
- const char *property_name,
- GVariantDict *dict)
-{
- GVariant *v;
-
- v = g_variant_dict_lookup_value (dict, property_name, NULL);
- if (!v)
- return;
- g_dbus_proxy_set_cached_property (proxy, property_name, v);
- g_variant_unref (v);
-}
-
static void
proxy_properties_changed_cb (GDBusProxy *proxy,
GVariant *changed_properties,
GStrv invalidated_properties,
GNetworkMonitorNM *nm)
{
- GVariantDict *dict;
-
- dict = g_variant_dict_new (changed_properties);
-
- update_cached_property (nm->priv->proxy, "Connectivity", dict);
-
- g_variant_dict_unref (dict);
-
sync_properties (nm, TRUE);
}
--
2.33.1

@ -0,0 +1,142 @@
From 85c4031696add9797e2334ced20678edcd96c869 Mon Sep 17 00:00:00 2001
From: Mart Raudsepp <leio@gentoo.org>
Date: Wed, 19 Dec 2018 16:22:21 +0200
Subject: [PATCH 1/2] tests: Allocate gvariant data from the heap to guarantee
alignment
On glib-2-58 branch we don't have !455, thus we need aligned data
for the gvariant tests to not fail on i686.
Fixes #1626
---
glib/tests/gvariant.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index 6e417f6c1..a7b19826d 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4664,6 +4664,7 @@ test_stack_dict_init (void)
static void
test_normal_checking_tuples (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
'a', '(', 'a', 'o', 'a', 'o', 'a', 'a', 'o', 'a', 'a', 'o', ')'
@@ -4672,13 +4673,15 @@ test_normal_checking_tuples (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
@@ -4790,6 +4793,7 @@ test_recursion_limits_array_in_variant (void)
static void
test_normal_checking_array_offsets (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x07, 0xe5, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'g',
@@ -4798,13 +4802,15 @@ test_normal_checking_array_offsets (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
@@ -4838,6 +4844,7 @@ test_normal_checking_tuple_offsets (void)
static void
test_normal_checking_empty_object_path (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
'(', 'h', '(', 'a', 'i', 'a', 'b', 'i', 'o', ')', ')',
@@ -4846,13 +4853,15 @@ test_normal_checking_empty_object_path (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
--
2.19.1
From 4ef58e5661849317a1110c9b93957f2c608677dd Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 3 Jan 2019 08:21:40 +0000
Subject: [PATCH 2/2] gvariant test: Also force alignment for tuple test data
glib!552 (commit 9eed22b3) fixed this for the tests that failed on i686,
but this additional test failed on Debian's s390x port
(IBM z/Architecture, 64-bit big-endian).
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/tests/gvariant.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index a7b19826d..c4a996c1f 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4820,6 +4820,7 @@ test_normal_checking_array_offsets (void)
static void
test_normal_checking_tuple_offsets (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x07, 0xe5, 0x00, 0x07, 0x00, 0x07,
'(', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', ')',
@@ -4828,13 +4829,15 @@ test_normal_checking_tuple_offsets (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
- FALSE, NULL, NULL);
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data,
+ size, FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
--
2.19.1

File diff suppressed because it is too large Load Diff

@ -0,0 +1,839 @@
%global _changelog_trimtime %(date +%s -d "1 year ago")
# See https://fedoraproject.org/wiki/Packaging:Python_Appendix#Manual_byte_compilation
%global __python %{__python3}
Name: glib2
Version: 2.56.4
Release: 161%{?dist}
Summary: A library of handy utility functions
License: LGPLv2+
URL: http://www.gtk.org
Source0: http://download.gnome.org/sources/glib/2.56/glib-%{version}.tar.xz
# For ghmac-gnutls.patch
BuildRequires: pkgconfig(gnutls)
BuildRequires: chrpath
BuildRequires: gettext
BuildRequires: perl-interpreter
# for sys/inotify.h
BuildRequires: glibc-devel
BuildRequires: libattr-devel
BuildRequires: libselinux-devel
# for sys/sdt.h
BuildRequires: systemtap-sdt-devel
BuildRequires: pkgconfig(libelf)
BuildRequires: pkgconfig(libffi)
BuildRequires: pkgconfig(libpcre)
BuildRequires: pkgconfig(mount)
BuildRequires: pkgconfig(zlib)
# Bootstrap build requirements
BuildRequires: automake autoconf libtool
BuildRequires: gtk-doc
BuildRequires: python3-devel
# for GIO content-type support
Recommends: shared-mime-info
# Implement RHEL 8 core crypto components policy
# https://bugzilla.redhat.com/show_bug.cgi?id=1630260
# https://gitlab.gnome.org/GNOME/glib/merge_requests/903
Patch0: ghmac-gnutls.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/50
Patch1: 50.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/309
Patch2: 309.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/403
Patch3: 409.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/546
Patch4: 546.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/876
Patch5: CVE-2019-12450.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/552
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/569
Patch6: gvariant-tests.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/105
Patch7: 105.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/532
Patch8: 532.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1777213
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1176
Patch9: 1176.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/450
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/603
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/974
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/984
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/985
Patch10: keyfile-backend.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/604
Patch11: CVE-2019-13012.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1942
Patch12: CVE-2021-27218.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1927
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2000
Patch13: CVE-2021-27219.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1981
Patch14: CVE-2021-28153.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1938284
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1369
Patch15: 1369.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1948988
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/873
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1353
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1691
Patch16: gmain-corruption.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1713
Patch17: 1713.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2244
Patch18: 2244.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2014652
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2291
Patch19: gnetworkmonitornm.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/13
Patch20: 13.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2125184
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1134.patch
Patch21: 1134.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/54
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/400
Patch22: 54.patch
%description
GLib is the low-level core library that forms the basis for projects
such as GTK+ and GNOME. It provides data structure handling for C,
portability wrappers, and interfaces for such runtime functionality
as an event loop, threads, dynamic loading, and an object system.
%package devel
Summary: A library of handy utility functions
Requires: %{name}%{?_isa} = %{version}-%{release}
%description devel
The glib2-devel package includes the header files for the GLib library.
%package doc
Summary: A library of handy utility functions
Requires: %{name} = %{version}-%{release}
BuildArch: noarch
%description doc
The glib2-doc package includes documentation for the GLib library.
%package fam
Summary: FAM monitoring module for GIO
Requires: %{name}%{?_isa} = %{version}-%{release}
BuildRequires: gamin-devel
%description fam
The glib2-fam package contains the FAM (File Alteration Monitor) module for GIO.
%package static
Summary: glib static
Requires: %{name}-devel = %{version}-%{release}
%description static
The %{name}-static subpackage contains static libraries for %{name}.
%package tests
Summary: Tests for the glib2 package
Requires: %{name}%{?_isa} = %{version}-%{release}
%description tests
The glib2-tests package contains tests that can be used to verify
the functionality of the installed glib2 package.
%prep
%autosetup -n glib-%{version} -p1
# restore timestamps after patching to appease multilib for .pyc files
tar vtf %{SOURCE0} | while read mode user size date time name; do touch -d "$date $time" ../$name; done
%build
autoreconf -f -i
# Bug 1324770: Also explicitly remove PCRE sources since we use --with-pcre=system
rm glib/pcre/*.[ch]
# Support builds of both git snapshots and tarballs packed with autogoo
(if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; CONFIGFLAGS=--enable-gtk-doc; fi;
%configure $CONFIGFLAGS \
--with-python=%{__python3} \
--with-pcre=system \
--enable-systemtap \
--enable-static \
--enable-installed-tests
)
%make_build
%install
# Use -p to preserve timestamps on .py files to ensure
# they're not recompiled with different timestamps
# to help multilib: https://bugzilla.redhat.com/show_bug.cgi?id=718404
%make_install INSTALL="install -p"
# Also since this is a generated .py file, set it to a known timestamp,
# otherwise it will vary by build time, and thus break multilib -devel
# installs.
touch -r gio/gdbus-2.0/codegen/config.py.in $RPM_BUILD_ROOT/%{_datadir}/glib-2.0/codegen/config.py
# patch0 changes the timestamp of codegen.py; reset it to a known value to not
# break multilib
touch -r gio/gdbus-2.0/codegen/config.py.in $RPM_BUILD_ROOT/%{_datadir}/glib-2.0/codegen/codegen.py
chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so
rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
rm -f $RPM_BUILD_ROOT%{_libdir}/gio/modules/*.{a,la}
rm -f $RPM_BUILD_ROOT%{_libexecdir}/installed-tests/glib/*.{a,la}
rm -f $RPM_BUILD_ROOT%{_libexecdir}/installed-tests/glib/modules/*.{a,la}
# Remove python files bytecompiled by the build system. rpmbuild regenerates
# them again later in a brp script using the timestamps set above.
rm -f $RPM_BUILD_ROOT%{_datadir}/glib-2.0/gdb/*.{pyc,pyo}
rm -rf $RPM_BUILD_ROOT%{_datadir}/glib-2.0/gdb/__pycache__/
rm -f $RPM_BUILD_ROOT%{_datadir}/glib-2.0/codegen/*.{pyc,pyo}
rm -rf $RPM_BUILD_ROOT%{_datadir}/glib-2.0/codegen/__pycache__/
mv $RPM_BUILD_ROOT%{_bindir}/gio-querymodules $RPM_BUILD_ROOT%{_bindir}/gio-querymodules-%{__isa_bits}
touch $RPM_BUILD_ROOT%{_libdir}/gio/modules/giomodule.cache
# bash-completion scripts need not be executable
chmod 644 $RPM_BUILD_ROOT%{_datadir}/bash-completion/completions/*
%find_lang glib20
%transfiletriggerin -- %{_libdir}/gio/modules
gio-querymodules-%{__isa_bits} %{_libdir}/gio/modules &> /dev/null || :
%transfiletriggerpostun -- %{_libdir}/gio/modules
gio-querymodules-%{__isa_bits} %{_libdir}/gio/modules &> /dev/null || :
%transfiletriggerin -- %{_datadir}/glib-2.0/schemas
glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%transfiletriggerpostun -- %{_datadir}/glib-2.0/schemas
glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%files -f glib20.lang
%license COPYING
%doc AUTHORS NEWS README
%{_libdir}/libglib-2.0.so.*
%{_libdir}/libgthread-2.0.so.*
%{_libdir}/libgmodule-2.0.so.*
%{_libdir}/libgobject-2.0.so.*
%{_libdir}/libgio-2.0.so.*
%dir %{_datadir}/bash-completion
%dir %{_datadir}/bash-completion/completions
%{_datadir}/bash-completion/completions/gdbus
%{_datadir}/bash-completion/completions/gsettings
%{_datadir}/bash-completion/completions/gapplication
%dir %{_datadir}/glib-2.0
%dir %{_datadir}/glib-2.0/schemas
%dir %{_libdir}/gio
%dir %{_libdir}/gio/modules
%ghost %{_libdir}/gio/modules/giomodule.cache
%{_bindir}/gio
%{_bindir}/gio-querymodules*
%{_bindir}/glib-compile-schemas
%{_bindir}/gsettings
%{_bindir}/gdbus
%{_bindir}/gapplication
%{_mandir}/man1/gio.1*
%{_mandir}/man1/gio-querymodules.1*
%{_mandir}/man1/glib-compile-schemas.1*
%{_mandir}/man1/gsettings.1*
%{_mandir}/man1/gdbus.1*
%{_mandir}/man1/gapplication.1*
%files devel
%{_libdir}/lib*.so
%{_libdir}/glib-2.0
%{_includedir}/*
%{_datadir}/aclocal/*
%{_libdir}/pkgconfig/*
%{_datadir}/glib-2.0/gdb
%{_datadir}/glib-2.0/gettext
%{_datadir}/glib-2.0/schemas/gschema.dtd
%{_datadir}/glib-2.0/valgrind/glib.supp
%{_datadir}/bash-completion/completions/gresource
%{_bindir}/glib-genmarshal
%{_bindir}/glib-gettextize
%{_bindir}/glib-mkenums
%{_bindir}/gobject-query
%{_bindir}/gtester
%{_bindir}/gdbus-codegen
%{_bindir}/glib-compile-resources
%{_bindir}/gresource
%{_datadir}/glib-2.0/codegen
%attr (0755, root, root) %{_bindir}/gtester-report
%{_mandir}/man1/glib-genmarshal.1*
%{_mandir}/man1/glib-gettextize.1*
%{_mandir}/man1/glib-mkenums.1*
%{_mandir}/man1/gobject-query.1*
%{_mandir}/man1/gtester-report.1*
%{_mandir}/man1/gtester.1*
%{_mandir}/man1/gdbus-codegen.1*
%{_mandir}/man1/glib-compile-resources.1*
%{_mandir}/man1/gresource.1*
%{_datadir}/gdb/
%{_datadir}/gettext/
%{_datadir}/systemtap/
%files doc
%doc %{_datadir}/gtk-doc/html/*
%files fam
%{_libdir}/gio/modules/libgiofam.so
%files static
%{_libdir}/libgio-2.0.a
%{_libdir}/libglib-2.0.a
%{_libdir}/libgmodule-2.0.a
%{_libdir}/libgobject-2.0.a
%{_libdir}/libgthread-2.0.a
%files tests
%{_libexecdir}/installed-tests
%{_datadir}/installed-tests
%changelog
* Tue Jan 03 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-161
- Backport grefcount API
- Resolves: #2153205
* Wed Nov 16 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-160
- Fix G_FILE_COPY_TARGET_DEFAULT_PERMS, should not create private files
- Resolves: #2125184
* Fri Apr 22 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-159
- Add --interface-info-[body|header] modes to gdbus-codegen
- Related: #2061994
* Wed Dec 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-158
- Fix GNetworkMonitor after NetworkManager D-Bus API changes
- Resolves: #2014652
* Wed Sep 15 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-157
- Fix g_get_user_database_entry() crash when used with nss-systemd
- Resolves: #2002126
* Thu Jul 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-156
- Fix test failure introduced in previous update
- Related: #1971533
* Wed Jun 23 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-14
- Refresh GHmac patchset
- Resolves: #1971533
* Thu May 20 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-13
- Rename and consolidate existing patches for better maintainability
- Refresh CVE-2021-27219 patcheset, using better-targeted fixes
Resolves: #1939108
* Wed May 05 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-12
- Fix various problems in GMainContext
Resolves: #1948988
* Tue May 04 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-11
- Remove CHARSETALIASDIR environment variable
Resolves: #1938284
* Wed Mar 31 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-10
- Fix CVE-2021-27218
Resolves: #1939072
- Fix CVE-2021-27219
Resolves: #1939108
- Fix CVE-2021-28153
Resolves: #1939118
* Tue Nov 10 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-9
- Update GHmac patch to implement g_hmac_copy()
Resolves: #1786538
- Update keyfile settings backend
Resolves: #1728896
- Fix CVE-2019-13012
Resolves: #1728632
* Mon Dec 02 2019 Colin Walters <walters@verbum.org> - 2.56.4-8
- Backport patches for GDBus auth
Resolves: #1777213
* Sat Jul 13 2019 Colin Walters <walters@redhat.com> - 2.56.4-7
- Backport patch for CVE-2019-12450
Resolves: #1722101
* Mon Jun 17 2019 Ray Strode <rstrode@redhat.com> - 2.56.4-5
- Backport glib2 change needed for accountsservice dbus
codegen fix
Resolves: #1713081
* Mon Jun 10 2019 Colin Walters <walters@redhat.com> - 2.56.4-4
- Back GHmac with GnuTLS for FIPS
- Resolves: #1630260
* Fri May 31 2019 Florian Müllner <fmuellner@redhat.com> - 2.56.4-3
- Backport per-desktop overrides
- Resolves: #1715951
* Tue Apr 02 2019 Colin Walters <walters@redhat.com> - 2.56.4-2
- Add system LDFLAGS
- Resolves: #1630566
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.4-1
- Update to 2.56.4
- Resolves: #1660859
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.1-7
- Remove .la files from -tests subpackage
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.1-6
- Fix multilib -devel installs
- Related: #1639428
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.1-5
- Fix gdbus codegen generated proxies breaking strict aliasing rules
- Resolves: #1639428
* Mon Dec 17 2018 Ray Strode <rstrode@redhat.com> - 2.56.1-4
- Ensure shared-mime-info is installed during testing
- Ensure test suite runs as unprivileged user
- Ensure test suite works when debugging is enabled
- Ensure echo-script from spawn test is marked executable
Related: #1625683
* Fri Dec 14 2018 Ray Strode <rstrode@redhat.com> - 2.56.1-3
- rebuild
Related: #1625683
* Mon Dec 10 2018 Josh Boyer <jwboyer@redhat.com> - 2.56.1-2
- Rebuild for CET note fixes
Resolves: #1657311
* Sun Apr 08 2018 Kalev Lember <klember@redhat.com> - 2.56.1-1
- Update to 2.56.1
* Mon Mar 12 2018 Kalev Lember <klember@redhat.com> - 2.56.0-1
- Update to 2.56.0
* Wed Feb 07 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.55.2-3
- Undo disabling mangling
* Wed Feb 07 2018 Kalev Lember <klember@redhat.com> - 2.55.2-2
- Disable brp-mangle-shebangs shebangs
* Wed Feb 07 2018 Kalev Lember <klember@redhat.com> - 2.55.2-1
- Update to 2.55.2
- Drop ldconfig scriptlets
* Wed Jan 31 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.55.1-3
- Switch to %%ldconfig_scriptlets
* Thu Jan 18 2018 Kalev Lember <klember@redhat.com> - 2.55.1-2
- gmain: Partial revert of recent wakeup changes
* Mon Jan 08 2018 Kalev Lember <klember@redhat.com> - 2.55.1-1
- Update to 2.55.1
- Drop upstreamed systemtap multilib fix
* Tue Dec 19 2017 Kalev Lember <klember@redhat.com> - 2.55.0-1
- Update to 2.55.0
* Wed Nov 01 2017 Kalev Lember <klember@redhat.com> - 2.54.2-1
- Update to 2.54.2
* Fri Oct 06 2017 Kalev Lember <klember@redhat.com> - 2.54.1-1
- Update to 2.54.1
* Mon Sep 11 2017 Kalev Lember <klember@redhat.com> - 2.54.0-1
- Update to 2.54.0
* Tue Sep 05 2017 Kalev Lember <klember@redhat.com> - 2.53.7-1
- Update to 2.53.7
* Sat Aug 19 2017 Kalev Lember <klember@redhat.com> - 2.53.6-1
- Update to 2.53.6
* Mon Aug 07 2017 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.53.5-1
- Update to 2.53.5
* Tue Aug 01 2017 Kalev Lember <klember@redhat.com> - 2.53.4-4
- Backport glib-mkenums flags annotation parsing fixes
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.53.4-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Fri Jul 21 2017 Kalev Lember <klember@redhat.com> - 2.53.4-2
- Revert a GKeyFile introspection ABI change
* Tue Jul 18 2017 Kalev Lember <klember@redhat.com> - 2.53.4-1
- Update to 2.53.4
* Thu Jun 22 2017 Kalev Lember <klember@redhat.com> - 2.53.3-1
- Update to 2.53.3
* Thu Jun 8 2017 Owen Taylor <otaylor@redhat.com> - 2.53.2-2
- Make triggers also compile schemas in /app/share/glib-2.0/schemas
* Wed May 24 2017 Florian Müllner <fmuellner@redhat.com> - 2.53.2-1
- Update to 2.53.2
* Mon May 15 2017 Kalev Lember <klember@redhat.com> - 2.52.2-2
- Backport a gmain GWakeup patch to fix timedatex high CPU usage (#1450628)
* Tue May 09 2017 Kalev Lember <klember@redhat.com> - 2.52.2-1
- Update to 2.52.2
* Tue Apr 11 2017 Colin Walters <walters@verbum.org> - 2.52.1-3
- Backport patches for gmain wakeup for qemu
See: https://bugzilla.gnome.org/show_bug.cgi?id=761102
* Tue Apr 11 2017 Colin Walters <walters@verbum.org> - 2.52.1-2
- Explictly remove PCRE sources
- Related: https://bugzilla.redhat.com/show_bug.cgi?id=1324770
* Tue Apr 11 2017 Kalev Lember <klember@redhat.com> - 2.52.1-1
- Update to 2.52.1
* Mon Mar 20 2017 Kalev Lember <klember@redhat.com> - 2.52.0-1
- Update to 2.52.0
* Thu Mar 16 2017 Kalev Lember <klember@redhat.com> - 2.51.5-1
- Update to 2.51.5
* Thu Mar 02 2017 Kalev Lember <klember@redhat.com> - 2.51.4-2
- Remove the dependency on dbus-launch again (#927212)
* Wed Mar 01 2017 David King <amigadave@amigadave.com> - 2.51.4-1
- Update to 2.51.4
- Add a Requires on dbus-launch (#927212)
- Use pkgconfig for BuildRequires
* Tue Feb 14 2017 Richard Hughes <rhughes@redhat.com> - 2.51.2-1
- Update to 2.51.2
* Mon Feb 13 2017 Richard Hughes <rhughes@redhat.com> - 2.51.1-1
- Update to 2.51.1
* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.51.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Mon Dec 19 2016 Miro Hrončok <mhroncok@redhat.com> - 2.51.0-2
- Rebuild for Python 3.6
* Sun Oct 30 2016 Kalev Lember <klember@redhat.com> - 2.51.0-1
- Update to 2.51.0
* Wed Oct 12 2016 Kalev Lember <klember@redhat.com> - 2.50.1-1
- Update to 2.50.1
* Mon Sep 19 2016 Kalev Lember <klember@redhat.com> - 2.50.0-1
- Update to 2.50.0
* Tue Sep 13 2016 Kalev Lember <klember@redhat.com> - 2.49.7-1
- Update to 2.49.7
- Don't set group tags
* Sun Aug 28 2016 Kalev Lember <klember@redhat.com> - 2.49.6-1
- Update to 2.49.6
* Thu Aug 18 2016 Kalev Lember <klember@redhat.com> - 2.49.5-1
- Update to 2.49.5
- Own /usr/share/gdb and /usr/share/systemtap directories
* Tue Aug 16 2016 Miro Hrončok <mhroncok@redhat.com> - 2.49.4-3
- Use Python 3 for the RPM Python byte compilation
* Wed Jul 27 2016 Ville Skyttä <ville.skytta@iki.fi> - 2.49.4-2
- Switch to Python 3 (#1286284)
* Thu Jul 21 2016 Kalev Lember <klember@redhat.com> - 2.49.4-1
- Update to 2.49.4
* Sun Jul 17 2016 Kalev Lember <klember@redhat.com> - 2.49.3-1
- Update to 2.49.3
* Wed Jun 22 2016 Richard Hughes <rhughes@redhat.com> - 2.49.2-1
- Update to 2.49.2
* Wed Jun 01 2016 Yaakov Selkowitz <yselkowi@redhat.com> - 2.49.1-2
- Soften shared-mime-info dependency (#1266118)
* Fri May 27 2016 Florian Müllner <fmuellner@redhat.com> - 2.49.1-1
- Update to 2.49.1
* Tue May 10 2016 Kalev Lember <klember@redhat.com> - 2.48.1-1
- Update to 2.48.1
* Wed Apr 06 2016 Colin Walters <walters@redhat.com> - 2.48.0-2
- Explicitly require system pcre, though we happened to default to this now
anyways due to something else pulling PCRE into the buildroot
Closes rhbz#1287266
* Tue Mar 22 2016 Kalev Lember <klember@redhat.com> - 2.48.0-1
- Update to 2.48.0
* Thu Mar 17 2016 Richard Hughes <rhughes@redhat.com> - 2.47.92-1
- Update to 2.47.92
* Wed Feb 24 2016 Colin Walters <walters@redhat.com> - 2.47.6.19.gad2092b-2
- git snapshot to work around https://bugzilla.gnome.org/show_bug.cgi?id=762637
- Add --with-python=/usr/bin/python explicitly to hopefully fix a weird
issue I am seeing where librepo fails to build in epel7 with this due to
us requiring /bin/python.
* Wed Feb 17 2016 Richard Hughes <rhughes@redhat.com> - 2.47.6-1
- Update to 2.47.6
* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 2.47.5-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Tue Jan 19 2016 David King <amigadave@amigadave.com> - 2.47.5-1
- Update to 2.47.5
* Wed Dec 16 2015 Kalev Lember <klember@redhat.com> - 2.47.4-1
- Update to 2.47.4
* Wed Nov 25 2015 Kalev Lember <klember@redhat.com> - 2.47.3-1
- Update to 2.47.3
* Wed Nov 25 2015 Kalev Lember <klember@redhat.com> - 2.47.2-1
- Update to 2.47.2
* Mon Nov 09 2015 Kevin Fenzi <kevin@scrye.com> - 2.47.1-2
- Add full path redirect output to null and || : to triggers.
* Wed Oct 28 2015 Kalev Lember <klember@redhat.com> - 2.47.1-1
- Update to 2.47.1
* Mon Oct 19 2015 Kalev Lember <klember@redhat.com> - 2.46.1-2
- Backport an upstream fix for app launching under wayland (#1273146)
* Wed Oct 14 2015 Kalev Lember <klember@redhat.com> - 2.46.1-1
- Update to 2.46.1
* Mon Sep 21 2015 Kalev Lember <klember@redhat.com> - 2.46.0-1
- Update to 2.46.0
* Mon Sep 14 2015 Kalev Lember <klember@redhat.com> - 2.45.8-1
- Update to 2.45.8
* Tue Sep 01 2015 Kalev Lember <klember@redhat.com> - 2.45.7-1
- Update to 2.45.7
* Wed Aug 19 2015 Kalev Lember <klember@redhat.com> - 2.45.6-1
- Update to 2.45.6
* Wed Aug 19 2015 Kalev Lember <klember@redhat.com> - 2.45.5-1
- Update to 2.45.5
* Fri Aug 14 2015 Matthias Clasen <mclasen@redhat.com> - 2.45.4-2
- Add file triggers for gio modules and gsettings schemas
* Tue Jul 21 2015 David King <amigadave@amigadave.com> - 2.45.4-1
- Update to 2.45.4
* Wed Jun 24 2015 Kalev Lember <klember@redhat.com> - 2.45.3-2
- Backport a patch to fix notification withdrawing in gnome-software
* Wed Jun 24 2015 David King <amigadave@amigadave.com> - 2.45.3-1
- Update to 2.45.3
* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.45.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Tue May 26 2015 David King <amigadave@amigadave.com> - 2.45.2-1
- Update to 2.45.2
* Thu Apr 30 2015 Kalev Lember <kalevlember@gmail.com> - 2.45.1-1
- Update to 2.45.1
* Mon Mar 23 2015 Kalev Lember <kalevlember@gmail.com> - 2.44.0-1
- Update to 2.44.0
* Tue Mar 17 2015 Kalev Lember <kalevlember@gmail.com> - 2.43.92-1
- Update to 2.43.92
* Mon Mar 02 2015 Kalev Lember <kalevlember@gmail.com> - 2.43.91-1
- Update to 2.43.91
* Sat Feb 21 2015 Till Maas <opensource@till.name> - 2.43.90-2
- Rebuilt for Fedora 23 Change
https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code
* Wed Feb 18 2015 David King <amigadave@amigadave.com> - 2.43.90-1
- Update to 2.43.90
- Update man pages glob in files section
* Tue Feb 10 2015 Matthias Clasen <mclasen@redhat.com> - 2.43.4-1
- Update to 2.43.4
* Tue Jan 20 2015 David King <amigadave@amigadave.com> - 2.43.3-1
- Update to 2.43.3
* Wed Dec 17 2014 Kalev Lember <kalevlember@gmail.com> - 2.43.2-1
- Update to 2.43.2
* Tue Nov 25 2014 Kalev Lember <kalevlember@gmail.com> - 2.43.1-1
- Update to 2.43.1
* Thu Oct 30 2014 Florian Müllner <fmuellner@redhat.com> - 2.43.0-1
- Update to 2.43.0
* Mon Sep 22 2014 Kalev Lember <kalevlember@gmail.com> - 2.42.0-1
- Update to 2.42.0
* Tue Sep 16 2014 Kalev Lember <kalevlember@gmail.com> - 2.41.5-1
- Update to 2.41.5
* Thu Sep 4 2014 Matthias Clasen <mclasen@redhat.com> 2.41.4-3
- Don't remove rpath from gdbus-peer test - it doesn't work without it
* Thu Sep 04 2014 Bastien Nocera <bnocera@redhat.com> 2.41.4-2
- Fix banshee getting selected as the default movie player
* Tue Sep 02 2014 Kalev Lember <kalevlember@gmail.com> - 2.41.4-1
- Update to 2.41.4
* Sat Aug 16 2014 Kalev Lember <kalevlember@gmail.com> - 2.41.3-1
- Update to 2.41.3
* Sat Aug 16 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.41.2-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild
* Wed Jul 23 2014 Stef Walter <stefw@redhat.com> - 2.41.2-2
- Fix regression with GDBus array encoding rhbz#1122128
* Mon Jul 14 2014 Kalev Lember <kalevlember@gmail.com> - 2.41.2-1
- Update to 2.41.2
* Sat Jul 12 2014 Tom Callaway <spot@fedoraproject.org> - 2.41.1-2
- fix license handling
* Tue Jun 24 2014 Richard Hughes <rhughes@redhat.com> - 2.41.1-1
- Update to 2.41.1
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.41.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
* Tue May 27 2014 Kalev Lember <kalevlember@gmail.com> - 2.41.0-1
- Update to 2.41.0
* Mon Mar 24 2014 Richard Hughes <rhughes@redhat.com> - 2.40.0-1
- Update to 2.40.0
* Tue Mar 18 2014 Richard Hughes <rhughes@redhat.com> - 2.39.92-1
- Update to 2.39.92
* Tue Mar 04 2014 Richard Hughes <rhughes@redhat.com> - 2.39.91-1
- Update to 2.39.91
* Tue Feb 18 2014 Richard Hughes <rhughes@redhat.com> - 2.39.90-1
- Update to 2.39.90
* Tue Feb 04 2014 Richard Hughes <rhughes@redhat.com> - 2.39.4-1
- Update to 2.39.4
* Tue Jan 14 2014 Richard Hughes <rhughes@redhat.com> - 2.39.3-1
- Update to 2.39.3
* Sun Dec 22 2013 Richard W.M. Jones <rjones@redhat.com> - 2.39.2-2
- Re-add static subpackage so that we can build static qemu as
an AArch64 binfmt.
* Tue Dec 17 2013 Richard Hughes <rhughes@redhat.com> - 2.39.2-1
- Update to 2.39.2
* Mon Dec 09 2013 Richard Hughes <rhughes@redhat.com> - 2.39.1-2
- Backport a patch from master to stop gnome-settings-daemon crashing.
* Thu Nov 14 2013 Richard Hughes <rhughes@redhat.com> - 2.39.1-1
- Update to 2.39.1
* Mon Oct 28 2013 Richard Hughes <rhughes@redhat.com> - 2.39.0-1
- Update to 2.39.0
* Tue Sep 24 2013 Kalev Lember <kalevlember@gmail.com> - 2.38.0-1
- Update to 2.38.0
* Tue Sep 17 2013 Kalev Lember <kalevlember@gmail.com> - 2.37.93-1
- Update to 2.37.93
* Mon Sep 02 2013 Kalev Lember <kalevlember@gmail.com> - 2.37.7-1
- Update to 2.37.7
* Wed Aug 21 2013 Debarshi Ray <rishi@fedoraproject.org> - 2.37.6-1
- Update to 2.37.6
* Sat Aug 03 2013 Petr Pisar <ppisar@redhat.com> - 2.37.5-2
- Perl 5.18 rebuild
* Thu Aug 1 2013 Debarshi Ray <rishi@fedoraproject.org> - 2.37.5-1
- Update to 2.37.5
* Wed Jul 17 2013 Petr Pisar <ppisar@redhat.com> - 2.37.4-2
- Perl 5.18 rebuild
* Tue Jul 9 2013 Matthias Clasen <mclasen@redhat.com> - 2.37.4-1
- Update to 2.37.4
* Thu Jun 20 2013 Debarshi Ray <rishi@fedoraproject.org> - 2.37.2-1
- Update to 2.37.2
* Tue May 28 2013 Matthias Clasen <mclasen@redhat.com> - 2.37.1-1
- Update to 2.37.1
- Add a tests subpackage
* Sat May 04 2013 Kalev Lember <kalevlember@gmail.com> - 2.37.0-1
- Update to 2.37.0
* Sat Apr 27 2013 Thorsten Leemhuis <fedora@leemhuis.info> - 2.36.1-2
- Fix pidgin freezes by applying patch from master (#956872)
* Mon Apr 15 2013 Kalev Lember <kalevlember@gmail.com> - 2.36.1-1
- Update to 2.36.1
* Mon Mar 25 2013 Kalev Lember <kalevlember@gmail.com> - 2.36.0-1
- Update to 2.36.0
* Tue Mar 19 2013 Matthias Clasen <mclasen@redhat.com> - 2.35.9-1
- Update to 2.35.9
* Thu Feb 21 2013 Kalev Lember <kalevlember@gmail.com> - 2.35.8-1
- Update to 2.35.8
* Tue Feb 05 2013 Kalev Lember <kalevlember@gmail.com> - 2.35.7-1
- Update to 2.35.7
* Tue Jan 15 2013 Matthias Clasen <mclasen@redhat.com> - 2.35.4-1
- Update to 2.35.4
* Thu Dec 20 2012 Kalev Lember <kalevlember@gmail.com> - 2.35.3-1
- Update to 2.35.3
* Sat Nov 24 2012 Kalev Lember <kalevlember@gmail.com> - 2.35.2-1
- Update to 2.35.2
* Thu Nov 08 2012 Kalev Lember <kalevlember@gmail.com> - 2.35.1-1
- Update to 2.35.1
- Drop upstreamed codegen-in-datadir.patch
Loading…
Cancel
Save