after running valgrind again with --leak-check=full and --show-reachable=yes, it appears that a great deal of the formally still reachable, but probably quite lost memory originates from e_cal_backend_cache_get_components() (e-cal-backend-cache.c line 473 specifically, which calls icalparser_parse_string()) It seems this function is identical in SVN
==1641== 5,393,785 bytes in 181,741 blocks are still reachable in loss record 102 of 107 ==1641== at 0x4C1FFAB: malloc (vg_replace_malloc.c:207) ==1641== by 0x9D16DE1: strdup (strdup.c:43) ==1641== by 0x6C61604: icalvalue_set_text (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C6167D: icalvalue_new_text (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C769E2: icalvalue_new_from_string_with_error (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C688BA: icalparser_add_line (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68CB8: icalparser_parse (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68F20: icalparser_parse_string (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x69DE5D6: e_cal_backend_cache_get_components (e-cal-backend-cache.c:473) ==1641== by 0xF4D20EA: synch_slave_loop (e-cal-backend-caldav.c:1259) ==1641== by 0x8FDDCA3: g_thread_create_proxy (gthread.c:635) ==1641== by 0x9A8C016: start_thread (pthread_create.c:297) ==1641== ==1641== ==1641== 7,568,054 bytes in 39,280 blocks are still reachable in loss record 103 of 107 ==1641== at 0x4C1F0BC: calloc (vg_replace_malloc.c:397) ==1641== by 0x8FBFA52: g_malloc0 (gmem.c:151) ==1641== by 0x8FABCC8: g_hash_table_new_full (ghash.c:358) ==1641== by 0x8FCE136: g_scanner_new (gscanner.c:228) ==1641== by 0x6ED64CA: e_sexp_new (in /usr/lib/libedataserver-1.2.so.9.1.0) ==1641== by 0x69DF470: e_cal_backend_sexp_new (e-cal-backend-sexp.c:1362) ==1641== by 0x69E61E7: impl_Cal_getQuery (e-data-cal.c:415) ==1641== by 0x82B3FA5: ORBit_small_invoke_adaptor (in /usr/lib/libORBit-2.so.0.1.0) ==1641== by 0x82C327F: (within /usr/lib/libORBit-2.so.0.1.0) ==1641== by 0x82C3839: (within /usr/lib/libORBit-2.so.0.1.0) ==1641== by 0x82AD374: giop_thread_queue_process (in /usr/lib/libORBit-2.so.0.1.0) ==1641== by 0x82ADB4E: (within /usr/lib/libORBit-2.so.0.1.0) ==1641== ==1641== ==1641== 10,416,032 bytes in 325,501 blocks are still reachable in loss record 104 of 107 ==1641== at 0x4C1FFAB: malloc (vg_replace_malloc.c:207) ==1641== by 0x6C7763A: pvl_new_element (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C776A1: pvl_push (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C6864C: icalparser_add_line (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68CB8: icalparser_parse (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68F20: icalparser_parse_string (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x69DE5D6: e_cal_backend_cache_get_components (e-cal-backend-cache.c:473) ==1641== by 0xF4D20EA: synch_slave_loop (e-cal-backend-caldav.c:1259) ==1641== by 0x8FDDCA3: g_thread_create_proxy (gthread.c:635) ==1641== by 0x9A8C016: start_thread (pthread_create.c:297) ==1641== by 0x9D665BC: clone (in /usr/lib/debug/libc-2.7.so) ==1641== ==1641== ==1641== 11,273,560 bytes in 281,839 blocks are still reachable in loss record 105 of 107 ==1641== at 0x4C1FFAB: malloc (vg_replace_malloc.c:207) ==1641== by 0x6C778DA: pvl_newlist (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C6A093: icalproperty_new_impl (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68617: icalparser_add_line (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68CB8: icalparser_parse (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68F20: icalparser_parse_string (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x69DE5D6: e_cal_backend_cache_get_components (e-cal-backend-cache.c:473) ==1641== by 0xF4D20EA: synch_slave_loop (e-cal-backend-caldav.c:1259) ==1641== by 0x8FDDCA3: g_thread_create_proxy (gthread.c:635) ==1641== by 0x9A8C016: start_thread (pthread_create.c:297) ==1641== by 0x9D665BC: clone (in /usr/lib/debug/libc-2.7.so) ==1641== ==1641== ==1641== 13,541,304 bytes in 241,809 blocks are still reachable in loss record 106 of 107 ==1641== at 0x4C1FFAB: malloc (vg_replace_malloc.c:207) ==1641== by 0x6C6A079: icalproperty_new_impl (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68617: icalparser_add_line (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68CB8: icalparser_parse (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68F20: icalparser_parse_string (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x69DE5D6: e_cal_backend_cache_get_components (e-cal-backend-cache.c:473) ==1641== by 0xF4D20EA: synch_slave_loop (e-cal-backend-caldav.c:1259) ==1641== by 0x8FDDCA3: g_thread_create_proxy (gthread.c:635) ==1641== by 0x9A8C016: start_thread (pthread_create.c:297) ==1641== by 0x9D665BC: clone (in /usr/lib/debug/libc-2.7.so) ==1641== ==1641== ==1641== 36,754,968 bytes in 241,809 blocks are still reachable in loss record 107 of 107 ==1641== at 0x4C1FFAB: malloc (vg_replace_malloc.c:207) ==1641== by 0x6C764A9: icalvalue_new_impl (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C6166A: icalvalue_new_text (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C769E2: icalvalue_new_from_string_with_error (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C688BA: icalparser_add_line (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68CB8: icalparser_parse (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x6C68F20: icalparser_parse_string (in /usr/lib/libecal-1.2.so.7.2.0) ==1641== by 0x69DE5D6: e_cal_backend_cache_get_components (e-cal-backend-cache.c:473) ==1641== by 0xF4D20EA: synch_slave_loop (e-cal-backend-caldav.c:1259) ==1641== by 0x8FDDCA3: g_thread_create_proxy (gthread.c:635) ==1641== by 0x9A8C016: start_thread (pthread_create.c:297) ==1641== by 0x9D665BC: clone (in /usr/lib/debug/libc-2.7.so) line #473 is calling icalparser_parse_string(), which parses a string and builds a complex icalcomponent* structure, which is then to be wrapped into an ECalComponent object and stashed into a list. The ECalComponent's destructor is responsible for deallocating the icalcomponent* structure. Line 1259 of e-cal-backend-caldav.c falls (again) within static void synchronize_cache(). synchronize_cache() attempts to match the GList of ECalComponent obtained from the ecal backend cache with items retrieved from the server (using caldav_server_list_objects). Initially, a hash table of all cached ECalComponent entries is built (L1262-L1274), without incrementing the ECalComponent refcounts. For each (server side) CalDAVObject, a match is attempted with the hash table. Each hit causes synchronize_object() to be called, in order to replicate the remote state into the local ECalComponent. The ECalComponent is also removed from the GList (and no refcount activity happens) [**] Each miss causes a leak of the CalDAVObject (image of the remote), as previously noted. The ECalComponent remains in both the GList and the GHashTable. At this point, the GList still contains all the ECalComponent for which either no match from server side was found, or for which matches failed. Each of these ECalComponent instances is removed from the backend cache, and if a notification needs to be raised, it is raised. Finally, the ECalComponent is unref'd. In the end, both the GList and the GHash are destroyed. In my copy of libglib2.0-0, neither is unreffing the contained values, since the hash table is built with a NULL last parameter. Sketch of a solution: * each addition to the hash table should g_object_ref(comp) * the hash table should be built with g_object_unref as its last parameter * caldav_object_free(object, FALSE) should also be called in the "object->status != 200" case. * the sobjs lists should be g_free()'d. -- Cyrille