src/kv_list.c

changeset 1365
e4135791687e
parent 1362
d886626a9526
equal deleted inserted replaced
1364:556e4e7608b1 1365:e4135791687e
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;
204 return kv_list->map_methods->get(map, key); 278 return kv_list->map_methods->get(map, key);
205 } 279 }
206 280
207 int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) { 281 int cx_kvl_map_remove(CxMap *map, CxHashKey key, void *targetbuf) {
208 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list; 282 cx_kv_list *kv_list = ((struct cx_kv_list_map_s*)map)->list;
283
209 void *node_data; 284 void *node_data;
210 if (kv_list->map_methods->remove(map, key, &node_data)) { 285 if (kv_list->map_methods->remove(map, key, &node_data)) {
211 return 1; 286 return 1;
212 } 287 }
213 // we cannot just call a list method (because we don't have the index) 288 // we cannot just call a list method (because we don't have the index)
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

mercurial