51 struct cx_kv_list_list_s list; |
51 struct cx_kv_list_list_s list; |
52 /** The lookup map - stores pointers to the nodes. */ |
52 /** The lookup map - stores pointers to the nodes. */ |
53 struct cx_kv_list_map_s *map; |
53 struct cx_kv_list_map_s *map; |
54 const cx_list_class *list_methods; |
54 const cx_list_class *list_methods; |
55 const cx_map_class *map_methods; |
55 const cx_map_class *map_methods; |
|
56 cx_destructor_func list_destr; |
|
57 cx_destructor_func2 list_destr2; |
|
58 void *list_destr_data; |
|
59 cx_destructor_func map_destr; |
|
60 cx_destructor_func2 map_destr2; |
|
61 void *map_destr_data; |
56 }; |
62 }; |
57 |
63 |
|
64 static void cx_kv_list_destructor_wrapper_list(void *list_ptr, void *elem) { |
|
65 const cx_kv_list *kv_list = list_ptr; |
|
66 // list destructor is already called with proper deref of the elem |
|
67 if (kv_list->list_destr) { |
|
68 kv_list->list_destr(elem); |
|
69 } |
|
70 if (kv_list->list_destr2) { |
|
71 kv_list->list_destr2(kv_list->list_destr_data, elem); |
|
72 } |
|
73 if (kv_list->map_destr) { |
|
74 kv_list->map_destr(elem); |
|
75 } |
|
76 if (kv_list->map_destr2) { |
|
77 kv_list->map_destr2(kv_list->map_destr_data, elem); |
|
78 } |
|
79 } |
|
80 |
|
81 static void cx_kv_list_destructor_wrapper_map(void *list_ptr, void *node_data) { |
|
82 const cx_kv_list *kv_list = list_ptr; |
|
83 // the elem called with a map destructor is a pointer to the node |
|
84 // we need to deref the elem accordingly |
|
85 void *elem = kv_list->list.list_base.collection.store_pointer ? *(void**)node_data : node_data; |
|
86 if (kv_list->list_destr) { |
|
87 kv_list->list_destr(elem); |
|
88 } |
|
89 if (kv_list->list_destr2) { |
|
90 kv_list->list_destr2(kv_list->list_destr_data, elem); |
|
91 } |
|
92 if (kv_list->map_destr) { |
|
93 kv_list->map_destr(elem); |
|
94 } |
|
95 if (kv_list->map_destr2) { |
|
96 kv_list->map_destr2(kv_list->map_destr_data, elem); |
|
97 } |
|
98 } |
|
99 |
|
100 static void cx_kv_list_update_destructors(cx_kv_list *list) { |
|
101 // we copy the destructors to our custom fields and register |
|
102 // an own destructor function which invokes all these |
|
103 if (list->list.list_base.collection.simple_destructor != NULL) { |
|
104 list->list_destr = list->list.list_base.collection.simple_destructor; |
|
105 list->list.list_base.collection.simple_destructor = NULL; |
|
106 } |
|
107 if (list->list.list_base.collection.advanced_destructor != cx_kv_list_destructor_wrapper_list) { |
|
108 list->list_destr2 = list->list.list_base.collection.advanced_destructor; |
|
109 list->list_destr_data = list->list.list_base.collection.destructor_data; |
|
110 list->list.list_base.collection.advanced_destructor = cx_kv_list_destructor_wrapper_list; |
|
111 list->list.list_base.collection.destructor_data = list; |
|
112 } |
|
113 if (list->map->map_base.base.collection.simple_destructor != NULL) { |
|
114 list->map_destr = list->map->map_base.base.collection.simple_destructor; |
|
115 list->map->map_base.base.collection.simple_destructor = NULL; |
|
116 } |
|
117 if (list->map->map_base.base.collection.advanced_destructor != cx_kv_list_destructor_wrapper_map) { |
|
118 list->map_destr2 = list->map->map_base.base.collection.advanced_destructor; |
|
119 list->map_destr_data = list->map->map_base.base.collection.destructor_data; |
|
120 list->map->map_base.base.collection.advanced_destructor = cx_kv_list_destructor_wrapper_map; |
|
121 list->map->map_base.base.collection.destructor_data = list; |
|
122 } |
|
123 } |
|
124 |
58 static void cx_kvl_deallocate(struct cx_list_s *list) { |
125 static void cx_kvl_deallocate(struct cx_list_s *list) { |
59 cx_kv_list *kv_list = (cx_kv_list*)list; |
126 cx_kv_list *kv_list = (cx_kv_list*)list; |
|
127 // patch the destructors |
|
128 cx_kv_list_update_destructors(kv_list); |
60 // free the map first |
129 // free the map first |
61 kv_list->map_methods->deallocate(&kv_list->map->map_base.base); |
130 kv_list->map_methods->deallocate(&kv_list->map->map_base.base); |
62 kv_list->list_methods->deallocate(list); |
131 kv_list->list_methods->deallocate(list); |
63 } |
132 } |
64 |
133 |
108 size_t index, |
177 size_t index, |
109 size_t num, |
178 size_t num, |
110 void *targetbuf |
179 void *targetbuf |
111 ) { |
180 ) { |
112 cx_kv_list *kv_list = (cx_kv_list*)list; |
181 cx_kv_list *kv_list = (cx_kv_list*)list; |
|
182 // patch the destructors |
|
183 cx_kv_list_update_destructors(kv_list); |
113 // TODO: always use the target buffer to get the element first, |
184 // TODO: always use the target buffer to get the element first, |
114 // then obtain the key, remove it from the map, |
185 // then obtain the key, remove it from the map, |
115 // and finally call any destructors manually |
186 // and finally call any destructors manually |
116 // TODO: map destructors are not called |
|
117 return kv_list->list_methods->remove(list, index, num, targetbuf); |
187 return kv_list->list_methods->remove(list, index, num, targetbuf); |
118 } |
188 } |
119 |
189 |
120 static void cx_kvl_clear(struct cx_list_s *list) { |
190 static void cx_kvl_clear(struct cx_list_s *list) { |
121 cx_kv_list *kv_list = (cx_kv_list*)list; |
191 cx_kv_list *kv_list = (cx_kv_list*)list; |
122 // FIXME: this is probably totally bugged, because |
192 // patch the destructors |
123 // a) the map may have destructors which are invoked triggering UAF |
193 // but remove the wrapper from the map to avoid calling it twice |
124 // b) the destructors registered with the map are not called for all list elements |
194 cx_kv_list_update_destructors(kv_list); |
|
195 cxDefineAdvancedDestructor(&kv_list->map->map_base.base, NULL, NULL); |
|
196 // clear the list |
125 kv_list->list_methods->clear(list); |
197 kv_list->list_methods->clear(list); |
126 // also clear all lookup entries |
198 // then clear the map |
127 cxMapClear(&kv_list->map->map_base.base); |
199 cxMapClear(&kv_list->map->map_base.base); |
128 } |
200 } |
129 |
201 |
130 static int cx_kvl_swap( |
202 static int cx_kvl_swap( |
131 struct cx_list_s *list, |
203 struct cx_list_s *list, |
148 struct cx_list_s *list, |
220 struct cx_list_s *list, |
149 const void *elem, |
221 const void *elem, |
150 bool remove |
222 bool remove |
151 ) { |
223 ) { |
152 cx_kv_list *kv_list = (cx_kv_list*)list; |
224 cx_kv_list *kv_list = (cx_kv_list*)list; |
153 // TODO: implement removal of the key in the map and calling the map destructors |
225 cx_kv_list_update_destructors(kv_list); |
|
226 // TODO: implement removal of the key in the map |
154 return kv_list->list_methods->find_remove(list, elem, remove); |
227 return kv_list->list_methods->find_remove(list, elem, remove); |
155 } |
228 } |
156 |
229 |
157 static void cx_kvl_sort(struct cx_list_s *list) { |
230 static void cx_kvl_sort(struct cx_list_s *list) { |
158 cx_kv_list *kv_list = (cx_kv_list*)list; |
231 cx_kv_list *kv_list = (cx_kv_list*)list; |
180 kv_list->list_methods->deallocate(&kv_list->list.list_base); |
253 kv_list->list_methods->deallocate(&kv_list->list.list_base); |
181 } |
254 } |
182 |
255 |
183 static void cx_kvl_map_clear(struct cx_map_s *map) { |
256 static void cx_kvl_map_clear(struct cx_map_s *map) { |
184 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
257 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
185 // TODO: iterate through the map elements and remove the key from the referenced list items |
258 cx_kv_list_update_destructors(kv_list); |
|
259 // TODO: iterate through the map elements, unlink them from the list, and free them |
186 kv_list->map_methods->clear(map); |
260 kv_list->map_methods->clear(map); |
187 } |
261 } |
188 |
262 |
189 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { |
263 static void *cx_kvl_map_put(CxMap *map, CxHashKey key, void *value) { |
190 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
264 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; |
215 // can have the node ptr directly instead) |
290 // can have the node ptr directly instead) |
216 // therefore, we re-implement the logic ourselves |
291 // therefore, we re-implement the logic ourselves |
217 |
292 |
218 // check if the outside caller want's us to return or to destroy the element |
293 // check if the outside caller want's us to return or to destroy the element |
219 if (targetbuf == NULL) { |
294 if (targetbuf == NULL) { |
220 // destroy the element |
295 // patch the destructors and invoke them through the wrapper |
221 // invoke all destructors from both the list and the map aspect |
296 cx_kv_list_update_destructors(kv_list); |
222 // (usually the user will only use one of the aspects anyway and if not, it's documented) |
297 cx_invoke_advanced_destructor(&kv_list->list.list_base, node_data); |
223 cx_invoke_destructor(&kv_list->list.list_base, node_data); |
|
224 // note that we cannot use the macro, because it will use the wrong store_pointer information |
|
225 CxMap *map_aspect = &kv_list->map->map_base.base; |
|
226 if (map_aspect->collection.simple_destructor) { |
|
227 map_aspect->collection.simple_destructor( |
|
228 kv_list->list.list_base.collection.store_pointer ? *(void**)node_data : node_data); |
|
229 } |
|
230 if (map_aspect->collection.advanced_destructor) { |
|
231 map_aspect->collection.advanced_destructor(map_aspect->collection.destructor_data, |
|
232 kv_list->list.list_base.collection.store_pointer ? *(void**)node_data : node_data); |
|
233 } |
|
234 } else { |
298 } else { |
235 // copy the element to the target buffer |
299 // copy the element to the target buffer |
236 memcpy(targetbuf, node_data, kv_list->list.list_base.collection.elem_size); |
300 memcpy(targetbuf, node_data, kv_list->list.list_base.collection.elem_size); |
237 } |
301 } |
238 |
302 |
314 struct cx_kv_list_map_s *kv_map = cxRealloc(allocator, map, sizeof(struct cx_kv_list_map_s)); |
378 struct cx_kv_list_map_s *kv_map = cxRealloc(allocator, map, sizeof(struct cx_kv_list_map_s)); |
315 |
379 |
316 // reallocate the list to add memory for storing the metadata |
380 // reallocate the list to add memory for storing the metadata |
317 cx_kv_list *kv_list = cxRealloc(allocator, list, sizeof(struct cx_kv_list_s)); |
381 cx_kv_list *kv_list = cxRealloc(allocator, list, sizeof(struct cx_kv_list_s)); |
318 |
382 |
|
383 // zero the custom destructor information |
|
384 memset((char*)kv_list + offsetof(cx_kv_list, list_destr), 0, sizeof(void*)*6); |
|
385 |
319 // if any of the reallocations failed, we bail out |
386 // if any of the reallocations failed, we bail out |
320 if (kv_map != NULL && kv_list != NULL) { |
387 if (kv_map != NULL && kv_list != NULL) { |
321 map = (CxMap*) kv_map; |
388 map = (CxMap*) kv_map; |
322 list = (CxList*) kv_list; |
389 list = (CxList*) kv_list; |
323 } else { // LCOV_EXCL_START |
390 } else { // LCOV_EXCL_START |