Out parameter from varargs leaks memory
Hello, I've probably found a memory leak when using GLib.VariantIter.next() in a while condition.
- Vala from git master - 0.43.2.17-2cea3
- This code snippets shows the issue and a workaround:
public HashTable<string, Variant?> to_hash_table(Variant variant) {
return_val_if_fail(variant.is_of_type(new VariantType("a{s*}")), null);
var result = new HashTable<string, Variant?>(str_hash, str_equal);
VariantIter iter = variant.iterator();
string? key = null;
Variant? val = null;
while (iter.next("{s*}", out key, out val)) {
if (key != null) {
result.insert(key, val);
}
// key = null; val = null; // <<< Workaround
}
return result;
}
void main() {
var builder = new VariantBuilder(new VariantType("a{smv}"));
builder.add("{smv}", "str1", new Variant.string("str"));
builder.add("{smv}", "str2", null);
builder.add("{smv}", "str3", new Variant.boolean(true));
var table = to_hash_table(builder.end());
builder = null;
table = null;
}
- This snippet from the generated C code shows where resources should be freed. The build command was:
valac --save-temps -X -g -X -O0 to_hashtable.vala
GHashTable*
to_hash_table (GVariant* variant)
{
GHashTable* _result_ = NULL;
GVariantIter* iter = NULL;
GVariantIter* _tmp5_;
gchar* key = NULL;
GVariant* val = NULL;
_tmp4_ = g_hash_table_new_full (...);
_result_ = _tmp4_;
_tmp5_ = g_variant_iter_new (variant);
iter = _tmp5_;
key = NULL;
val = NULL;
while (TRUE) {
GVariantIter* _tmp6_;
const gchar* _tmp7_;
_tmp6_ = iter;
// >>> Old values of key and val are not freed before
// >>> g_variant_iter_next, which returns a copy of a string
// >>> (key) and increases reference of the Variant value (val).
if (!g_variant_iter_next (_tmp6_, "{s*}", &key, &val, NULL)) {
break;
}
_tmp7_ = key;
if (_tmp7_ != NULL) {
GHashTable* _tmp8_;
const gchar* _tmp9_;
gchar* _tmp10_;
GVariant* _tmp11_;
GVariant* _tmp12_;
_tmp8_ = _result_;
_tmp9_ = key;
_tmp10_ = g_strdup (_tmp9_);
_tmp11_ = val;
_tmp12_ = _g_variant_ref0 (_tmp11_);
g_hash_table_insert (_tmp8_, _tmp10_, _tmp12_);
}
}
result = _result_;
_g_variant_unref0 (val);
_g_free0 (key);
_g_variant_iter_free0 (iter);
return result;
}
-
valgrind.log from
G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --leak-check=full --leak-resolution=high --num-callers=20 --suppressions=/usr/share/glib-2.0/valgrind/glib.supp --log-file=valgrind.log ./to_hashtable
Thanks for your work on Vala :-)
Edited by Al Thomas