GNOME Bugzilla – Bug 554844
Vala generated C Code leaks when using a "type instance" derived class
Last modified: 2008-12-30 21:28:46 UTC
Please describe the problem: Seems that vala generated C Code leaks when using a vala "class" (GLib type instance derived one). All is ok when I derive from GLib.Object Steps to reproduce: Actual results: Expected results: Does this happen every time? Yes Other information:
This is my vala test program source: using GLib; using Gee; namespace Leaks { public class Item { public string field = null; } public class Items { public Gee.List<Item> items = new Gee.ArrayList<Item> (); } public static void main (string[] args) { var test = new Items (); test.items.add (new Item ()); test = null; return; } } This is my valgrind output: andrea@spavento:~/documenti/src/vala/tests/valas/leaks$ G_SLICE=always-malloc G_DEBUG=gc-friendly GLIBCPP_FORCE_NEW=1 GLIBCXX_FORCE_NEW=1 valgrind --leak-check=full --show-reachable=yes ./gee-test-a ==5272== Memcheck, a memory error detector. ==5272== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al. ==5272== Using LibVEX rev 1854, a library for dynamic binary translation. ==5272== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP. ==5272== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation framework. ==5272== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al. ==5272== For more details, rerun with: -v ==5272== ==5272== ==5272== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from 1) ==5272== malloc/free: in use at exit: 15,324 bytes in 414 blocks. ==5272== malloc/free: 659 allocs, 245 frees, 190,755 bytes allocated. ==5272== For counts of detected errors, rerun with: -v ==5272== searching for pointers to 414 not-freed blocks. ==5272== checked 89,944 bytes. ==5272== ==5272== 16 bytes in 1 blocks are indirectly lost in loss record 1 of 8 ==5272== at 0x4023D6E: malloc (vg_replace_malloc.c:207) ==5272== by 0x40D19D3: g_malloc (gmem.c:131) ==5272== by 0x40E8302: g_slice_alloc (gslice.c:824) ==5272== by 0x40E8634: g_slice_alloc0 (gslice.c:833) ==5272== by 0x407D94A: g_type_create_instance (gtype.c:1654) ==5272== by 0x8048876: leaks_item_new (gee-test-a.vala:8) ==5272== by 0x8048A99: leaks_main (gee-test-a.vala:20) ==5272== by 0x8048B4E: main (gee-test-a.vala:16) ==5272== ==5272== ==5272== 16 bytes in 1 blocks are indirectly lost in loss record 2 of 8 ==5272== at 0x4021E22: calloc (vg_replace_malloc.c:397) ==5272== by 0x40D195B: g_malloc0 (gmem.c:151) ==5272== by 0x404322E: (within /usr/lib/libgee.so.0.0.0) ==5272== by 0x407DD02: g_type_create_instance (gtype.c:1674) ==5272== by 0x40622E4: g_object_constructor (gobject.c:1334) ==5272== by 0x4062B15: g_object_newv (gobject.c:1211) ==5272== by 0x4043C97: gee_array_list_new (in /usr/lib/libgee.so.0.0.0) ==5272== by 0x80489B8: leaks_items_instance_init (gee-test-a.vala:24) ==5272== by 0x407DD02: g_type_create_instance (gtype.c:1674) ==5272== by 0x8048965: leaks_items_new (gee-test-a.vala:13) ==5272== by 0x8048A8A: leaks_main (gee-test-a.vala:20) ==5272== by 0x8048B4E: main (gee-test-a.vala:16) ==5272== ==5272== ==5272== 80 (48 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 8 ==5272== at 0x4023D6E: malloc (vg_replace_malloc.c:207) ==5272== by 0x40D19D3: g_malloc (gmem.c:131) ==5272== by 0x40E8302: g_slice_alloc (gslice.c:824) ==5272== by 0x40E8634: g_slice_alloc0 (gslice.c:833) ==5272== by 0x407D94A: g_type_create_instance (gtype.c:1654) ==5272== by 0x40622E4: g_object_constructor (gobject.c:1334) ==5272== by 0x4062B15: g_object_newv (gobject.c:1211) ==5272== by 0x4043C97: gee_array_list_new (in /usr/lib/libgee.so.0.0.0) ==5272== by 0x80489B8: leaks_items_instance_init (gee-test-a.vala:24) ==5272== by 0x407DD02: g_type_create_instance (gtype.c:1674) ==5272== by 0x8048965: leaks_items_new (gee-test-a.vala:13) ==5272== by 0x8048A8A: leaks_main (gee-test-a.vala:20) ==5272== ==5272== ==5272== 2,360 bytes in 14 blocks are still reachable in loss record 5 of 8 ==5272== at 0x4023E8C: realloc (vg_replace_malloc.c:429) ==5272== by 0x40D18B9: g_realloc (gmem.c:170) ==5272== by 0x405AD93: g_boxed_type_register_static (gbsearcharray.h:216) ==5272== by 0x405B1A5: g_value_array_get_type (gboxed.c:171) ==5272== by 0x4068B54: g_param_spec_types_init (gparamspecs.c:1451) ==5272== by 0x40788DC: g_type_init_with_debug_flags (gtype.c:4067) ==5272== by 0x4078941: g_type_init (gtype.c:4091) ==5272== by 0x8048B3D: main (gee-test-a.vala:16) ==5272== ==5272== ==5272== 2,456 bytes in 54 blocks are still reachable in loss record 6 of 8 ==5272== at 0x4023D6E: malloc (vg_replace_malloc.c:207) ==5272== by 0x4023EEF: realloc (vg_replace_malloc.c:429) ==5272== by 0x40D18B9: g_realloc (gmem.c:170) ==5272== by 0x40B4F08: g_quark_from_static_string (gdataset.c:683) ==5272== by 0x4078750: g_type_init_with_debug_flags (gtype.c:4012) ==5272== by 0x4078941: g_type_init (gtype.c:4091) ==5272== by 0x8048B3D: main (gee-test-a.vala:16) ==5272== ==5272== ==5272== 3,012 bytes in 168 blocks are still reachable in loss record 7 of 8 ==5272== at 0x4023D6E: malloc (vg_replace_malloc.c:207) ==5272== by 0x40D19D3: g_malloc (gmem.c:131) ==5272== by 0x40E8302: g_slice_alloc (gslice.c:824) ==5272== by 0x40BB898: g_hash_table_new_full (ghash.c:347) ==5272== by 0x40BB927: g_hash_table_new (ghash.c:318) ==5272== by 0x40B4F3A: g_quark_from_static_string (gdataset.c:687) ==5272== by 0x4078750: g_type_init_with_debug_flags (gtype.c:4012) ==5272== by 0x4078941: g_type_init (gtype.c:4091) ==5272== by 0x8048B3D: main (gee-test-a.vala:16) ==5272== ==5272== ==5272== 6,536 bytes in 153 blocks are still reachable in loss record 8 of 8 ==5272== at 0x4021E22: calloc (vg_replace_malloc.c:397) ==5272== by 0x40D195B: g_malloc0 (gmem.c:151) ==5272== by 0x40E65EA: g_slice_init_nomessage (gslice.c:329) ==5272== by 0x40E8374: g_slice_alloc (gslice.c:359) ==5272== by 0x40BB898: g_hash_table_new_full (ghash.c:347) ==5272== by 0x40BB927: g_hash_table_new (ghash.c:318) ==5272== by 0x40B4F3A: g_quark_from_static_string (gdataset.c:687) ==5272== by 0x4078750: g_type_init_with_debug_flags (gtype.c:4012) ==5272== by 0x4078941: g_type_init (gtype.c:4091) ==5272== by 0x8048B3D: main (gee-test-a.vala:16) ==5272== ==5272== LEAK SUMMARY: ==5272== definitely lost: 48 bytes in 1 blocks. ==5272== indirectly lost: 32 bytes in 2 blocks. ==5272== possibly lost: 0 bytes in 0 blocks. ==5272== still reachable: 14,364 bytes in 389 blocks. ==5272== suppressed: 880 bytes in 22 blocks.
Forgot to mention that setting items collection to null solves the leak: using GLib; using Gee; namespace Leaks { public class Item { public string field = null; } public class Items { public Gee.List<Item> items = new Gee.ArrayList<Item> (); } public static void main (string[] args) { var test = new Items (); test.items.add (new Item ()); // THIS SOLVES THE LEAK test.items = null; test = null; return; } }
Created attachment 120012 [details] [review] Unfinished patch This patch try to fix the leaks. With this applied I get ==867== LEAK SUMMARY: ==867== definitely lost: 0 bytes in 0 blocks. ==867== possibly lost: 880 bytes in 22 blocks. ==867== still reachable: 14,620 bytes in 398 blocks. ==867== suppressed: 0 bytes in 0 blocks. And the finalizers seems correct (warning my first time seeing a glib fundamental type), but testing it against libvala itself result in the same huge leak.
Created attachment 120013 [details] Program used to test if libvala is memory leak free Compiled with: valac --save-temps leaks.vala --pkg vala-1.0 Checked with: G_SLICE=always-malloc G_DEBUG=gc-friendly GLIBCPP_FORCE_NEW=1 GLIBCXX_FORCE_NEW=1 valgrind --leak-check=full --show-reachable=yes ./leaks
Finally I've found it, this case still leaks: using GLib; namespace Leaks { [Compact] private class Node<G> { public G key; public Node (G# k) { key = #k; } } public class Item { public string field = null; public Item (string name) { this.field = name; } } public static void main (string[] args) { var node = new Node<Item> (new Item ("1234")); return; } }
Created attachment 120058 [details] [review] A better patch (still uncomplete) This patch solves almost all the leaks. As a reminder this is what I've found until now: 1) Vala classes (derived just from GTypeInstance) leaks because they don't free their own fields [the patch solves this] 2) Every classes that derives from a fundamental type (1) leaks because they don't free their own fields as in (1) and in that case they need to chain up the destructor [the patch solves this] 3) Every non gobject class isn't freed in the destruction process because vala can't generate a correct unref statement for it [the patch solves this] 4) Every generic compact class leaks the generic values if the ownership is tranferred [the patch *DOESN'T* solve this, but *REMOVES* the [Compact] attribute in the gee hashset & hashmap classes so that they can became normal "vala classes"]
2008-10-17 Jürg Billeter <j@bitron.ch> * gobject/valaccodeclassbinding.vala: * gobject/valaccodegenerator.vala: * vapi/glib-2.0.vapi: Fix leaks in non-GObject classes, based on patch by Andrea Del Signore, fixes bug 554844 Fixed in r1850.
*** Bug 547829 has been marked as a duplicate of this bug. ***