From 4a4415984abf7752615ea1da75276cffbcd6995f Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Wed, 17 May 2017 09:09:13 +0200 Subject: [PATCH] gdbus: Don't leak nested HashTable on deserialization Additionally make sure types derived from string are freed, e.g. ObjectPath https://bugzilla.gnome.org/show_bug.cgi?id=782719 --- codegen/valagvariantmodule.vala | 10 ++++-- tests/Makefile.am | 1 + tests/dbus/bug782719.test | 63 +++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 tests/dbus/bug782719.test diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala index b50aca02c..b3ff1cf51 100644 --- a/codegen/valagvariantmodule.vala +++ b/codegen/valagvariantmodule.vala @@ -394,7 +394,7 @@ public class Vala.GVariantModule : GAsyncModule { ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator (value_name)); var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full")); - if (key_type.data_type == string_type.data_type) { + if (key_type.data_type.is_subtype_of (string_type.data_type)) { hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash")); hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal")); } else if (key_type.data_type == gvariant_type) { @@ -405,18 +405,22 @@ public class Vala.GVariantModule : GAsyncModule { hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal")); } - if (key_type.data_type == string_type.data_type) { + if (key_type.data_type.is_subtype_of (string_type.data_type)) { hash_table_new.add_argument (new CCodeIdentifier ("g_free")); } else if (key_type.data_type == gvariant_type) { hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify")); + } else if (key_type.data_type.get_full_name () == "GLib.HashTable") { + hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify")); } else { hash_table_new.add_argument (new CCodeIdentifier ("NULL")); } - if (value_type.data_type == string_type.data_type) { + if (value_type.data_type.is_subtype_of (string_type.data_type)) { hash_table_new.add_argument (new CCodeIdentifier ("g_free")); } else if (value_type.data_type == gvariant_type) { hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_variant_unref"), "GDestroyNotify")); + } else if (value_type.data_type.get_full_name () == "GLib.HashTable") { + hash_table_new.add_argument (new CCodeCastExpression (new CCodeIdentifier ("g_hash_table_unref"), "GDestroyNotify")); } else { hash_table_new.add_argument (new CCodeIdentifier ("NULL")); } diff --git a/tests/Makefile.am b/tests/Makefile.am index 2a2f4d43c..62538bee6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -277,6 +277,7 @@ TESTS = \ dbus/dicts.test \ dbus/bug596862.vala \ dbus/bug602003.test \ + dbus/bug782719.test \ dbus/rawvariants.test \ gir/bug651773.test \ gir/bug667751.test \ diff --git a/tests/dbus/bug782719.test b/tests/dbus/bug782719.test new file mode 100644 index 000000000..fe52eb3e2 --- /dev/null +++ b/tests/dbus/bug782719.test @@ -0,0 +1,63 @@ +Packages: gio-2.0 +D-Bus + +Program: client + +[DBus (name = "org.example.Test")] +interface Test : Object { + public abstract HashTable> test_nested_dict () throws IOError; +} + +void main () { + // client + Test test = Bus.get_proxy_sync (BusType.SESSION, "org.example.Test", "/org/example/test"); + + HashTable> dict = test.test_nested_dict (); + assert (dict.size () == 1); + HashTable nested_dict = dict.lookup ("hello"); + assert (nested_dict != null); + Variant v = nested_dict.lookup ("hello"); + assert (v != null); + string[] s = (string[]) v; + assert (s.length == 1 && s[0] == "hello"); +} + +Program: server + +[DBus (name = "org.example.Test")] +class Test : Object { + public HashTable> test_nested_dict () { + string[] s = { "hello" }; + HashTable nested_dict = new HashTable (str_hash, null); + nested_dict.insert ("hello", s); + HashTable> dict = new HashTable> (str_hash, null); + dict.insert ("hello", nested_dict); + return dict; + } +} + +MainLoop main_loop; + +void client_exit (Pid pid, int status) { + // client finished, terminate server + assert (status == 0); + main_loop.quit (); +} + +void main () { + var conn = Bus.get_sync (BusType.SESSION); + conn.register_object ("/org/example/test", new Test ()); + + // try to register service in session bus + var request_result = conn.call_sync ("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "RequestName", + new Variant ("(su)", "org.example.Test", 0x4), null, 0, -1); + assert ((uint) request_result.get_child_value (0) == 1); + + // server ready, spawn client + Pid client_pid; + Process.spawn_async (null, { "test", "/dbus/bug782719/client" }, null, SpawnFlags.DO_NOT_REAP_CHILD, null, out client_pid); + ChildWatch.add (client_pid, client_exit); + + main_loop = new MainLoop (); + main_loop.run (); +} -- 2.47.3