diff options
author | Ole André Vadla Ravnås <oleavr@gmail.com> | 2016-10-04 17:11:00 +0000 |
---|---|---|
committer | Maciej Piechotka <uzytkownik2@gmail.com> | 2016-10-11 16:25:25 -0700 |
commit | 707456e37bded83b28d8bb8e21bab80c02359611 (patch) | |
tree | ecff9573feebdec0b8f553ea97999a3242cb05ab | |
parent | 2a32dd2f6e51d2363d9cf7af5d05d5d4ac9070e9 (diff) | |
download | libgee-707456e37bded83b28d8bb8e21bab80c02359611.tar.gz |
Fix use-after-frees caused by weak pointer issues
Same issue in HashMap and TreeMap:
```
==3251==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000870 at pc 0x000108be666b bp 0x7fff571e62b0 sp 0x7fff571e62a8
WRITE of size 8 at 0x604000000870 thread T0
#0 0x108be666a in g_nullify_pointer gutils.c:2051
#1 0x108b8c906 in weak_refs_notify gobject.c:2638
#2 0x108bbb17c in g_data_set_internal gdataset.c:407
#3 0x108b887db in g_object_unref gobject.c:3148
#4 0x108a4b0ec in map_tests_test_entry_weak_pointer_lifetime testmap.c:1358
0x604000000870 is located 32 bytes inside of 40-byte region [0x604000000850,0x604000000878)
freed by thread T0 here:
#0 0x1090f0e29 in wrap_free (libclang_rt.asan_osx_dynamic.dylib+0x4ae29)
#1 0x108ace566 in gee_hash_map_unset_helper hashmap.c:1692
#2 0x108acc534 in gee_hash_map_real_unset hashmap.c:1520
#3 0x108a4b0df in map_tests_test_entry_weak_pointer_lifetime testmap.c:1357
previously allocated by thread T0 here:
#0 0x1090f0c60 in wrap_malloc (libclang_rt.asan_osx_dynamic.dylib+0x4ac60)
#1 0x108bce848 in g_malloc gmem.c:95
#2 0x108bd6585 in g_slice_alloc gslice.c:1012
#3 0x108bd6bee in g_slice_alloc0 gslice.c:1038
#4 0x108acdc27 in gee_hash_map_node_new hashmap.c:2084
#5 0x108acc277 in gee_hash_map_real_set hashmap.c:1494
#6 0x108a4b032 in map_tests_test_entry_weak_pointer_lifetime testmap.c:1311
https://bugzilla.gnome.org/show_bug.cgi?id=772418
-rw-r--r-- | gee/hashmap.vala | 6 | ||||
-rw-r--r-- | gee/treemap.vala | 6 | ||||
-rw-r--r-- | tests/testmap.vala | 16 |
3 files changed, 27 insertions, 1 deletions
diff --git a/gee/hashmap.vala b/gee/hashmap.vala index b1767e3..83243a7 100644 --- a/gee/hashmap.vala +++ b/gee/hashmap.vala @@ -341,6 +341,12 @@ public class Gee.HashMap<K,V> : Gee.AbstractMap<K,V> { key_hash = hash; entry = null; } + + ~Node () { + if (entry != null) { + entry.remove_weak_pointer ((void**) (&entry)); + } + } } private class Entry<K,V> : Map.Entry<K,V> { diff --git a/gee/treemap.vala b/gee/treemap.vala index d151d27..5c1c4cd 100644 --- a/gee/treemap.vala +++ b/gee/treemap.vala @@ -507,6 +507,12 @@ public class Gee.TreeMap<K,V> : Gee.AbstractBidirSortedMap<K,V> { } } + ~Node () { + if (entry != null) { + entry.remove_weak_pointer ((void**) (&entry)); + } + } + public void flip () { color = color.flip (); if (left != null) { diff --git a/tests/testmap.vala b/tests/testmap.vala index 5a63cf8..468d477 100644 --- a/tests/testmap.vala +++ b/tests/testmap.vala @@ -35,6 +35,7 @@ public abstract class MapTests : Gee.TestCase { add_test ("[Map] keys", test_keys); add_test ("[Map] values", test_values); add_test ("[Map] entries", test_entries); + add_test ("[Map] entry weak pointer lifetime", test_entry_weak_pointer_lifetime); add_test ("[Map] set all", test_set_all); add_test ("[Map] unset all", test_unset_all); add_test ("[Map] has all", test_has_all); @@ -283,7 +284,20 @@ public abstract class MapTests : Gee.TestCase { entries = test_map.entries; assert (entries.size == 0); } - + + private void test_entry_weak_pointer_lifetime () { + // Issue was reproducible with AddressSanitizer and G_SLICE=always-malloc + + test_map["1337"] = "Badger"; + + foreach (var entry in test_map.entries) { + if (entry.value == "Badger") { + test_map.unset (entry.key); + break; + } + } + } + public void test_clear () { test_map.set ("one", "value_of_one"); test_map.set ("two", "value_of_two"); |