On Fri, Dec 09, 2011 at 05:24:06PM +0100, Jan Friesse wrote:
Hi (Angus), I found problem with map and libqb. Attached is simplest reproducer which I was able to create.
Thanks Honza, I'll look into it asap.
-Angus
Result is following: Iter test.key1 = 0x5a2a290 (1) Freeing value Notify (nil) 0x5a2a290==15090== Invalid read of size 4 ==15090== at 0x400988: notify_fn (in /root/a.out) ==15090== by 0x4E47190: trie_notify (trie.c:297) ==15090== by 0x4E46C37: trie_node_destroy (trie.c:125) ==15090== by 0x4E46C90: trie_node_deref (trie.c:138) ==15090== by 0x4E4762E: trie_iter_next (trie.c:437) ==15090== by 0x4E44D30: qb_map_iter_next (map.c:82) ==15090== by 0x400B33: main (in /root/a.out) ==15090== Address 0x5a2a290 is 0 bytes inside a block of size 8 free'd ==15090== at 0x4C2695D: free (vg_replace_malloc.c:366) ==15090== by 0x400B20: main (in /root/a.out) ==15090== old value = 1 Iter test.key2 = 0x5a2a2e0 (2) Freeing value Notify (nil) 0x5a2a2e0old value = 2 ==15090== ==15090== HEAP SUMMARY: ==15090== in use at exit: 4,304 bytes in 25 blocks ==15090== total heap usage: 29 allocs, 4 frees, 4,800 bytes allocated ==15090== ==15090== LEAK SUMMARY: ==15090== definitely lost: 32 bytes in 1 blocks ==15090== indirectly lost: 4,272 bytes in 24 blocks ==15090== possibly lost: 0 bytes in 0 blocks ==15090== still reachable: 0 bytes in 0 blocks ==15090== suppressed: 0 bytes in 0 blocks ==15090== Rerun with --leak-check=full to see details of leaked memory ==15090== ==15090== For counts of detected and suppressed errors, rerun with: -v ==15090== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 6 from 6)
There should be NO invalid read of size ... Main problem seems to be with fact, that delete callback is called after free in iter, but in that time, pointer is already freed. Possible workaround may be to free value only in callback, but it can be very hard (impossible) to realize.
Regards, Honza
/*
- Compile as gcc -lqb libqb_map_bug.c
*/ #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <qb/qbdefs.h> #include <qb/qbutil.h> #include <qb/qbmap.h>
void notify_fn(uint32_t event, char* key, void* old_value, void* value, void* user_data) { fprintf(stderr, "Notify %p %p", value, old_value);
if (value != NULL) fprintf(stderr, "value = %u\n", *(int *)value); if (old_value != NULL) fprintf(stderr, "old value = %u\n", *(int *)old_value); }
int main(void) { qb_map_t *trie; int *i1, *i2; qb_map_iter_t *iter; const char *key; void *val;
trie = qb_trie_create(); assert(trie != NULL);
i1 = malloc(sizeof(i1)); assert(i1 != NULL); i2 = malloc(sizeof(i2)); assert(i2 != NULL); *i1 = 1; *i2 = 2; qb_map_put(trie, "test.key1", i1); qb_map_put(trie, "test.key2", i2);
qb_map_notify_add(trie, "test.", notify_fn, QB_MAP_NOTIFY_DELETED | QB_MAP_NOTIFY_REPLACED | QB_MAP_NOTIFY_INSERTED | QB_MAP_NOTIFY_RECURSIVE, NULL);
iter = qb_map_pref_iter_create(trie, "test."); while ((key = qb_map_iter_next(iter, &val)) != NULL) { fprintf(stderr,"Iter %s = %p (%u)\n", key, val, *(int*)val); qb_map_rm(trie, key); fprintf(stderr, "Freeing value\n"); free(val); }
return (0); }
quarterback-devel mailing list quarterback-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/quarterback-devel