summaryrefslogtreecommitdiffstats
path: root/src/plist.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2023-02-05 13:42:23 +0100
committerGravatar Nikias Bassen2023-02-05 13:42:23 +0100
commit52826a6c229ed3e353d4dae711a6c52a96d99764 (patch)
treebbff0a7bbea4e62f7646174ee245e5950b4b0d30 /src/plist.c
parent706771e357570d1bee268fc7c2233506da967bcd (diff)
downloadlibplist-52826a6c229ed3e353d4dae711a6c52a96d99764.tar.gz
libplist-52826a6c229ed3e353d4dae711a6c52a96d99764.tar.bz2
Fix plist_sort() by swapping the nodes in the tree instead of their data
The problem was that we swapped potential child node data between nodes, but their parents would not be updated that way, leading to double frees or segmentation faults when freeing a plist. This commit instead fixes this by swapping the actual nodes in the tree.
Diffstat (limited to 'src/plist.c')
-rw-r--r--src/plist.c62
1 files changed, 33 insertions, 29 deletions
diff --git a/src/plist.c b/src/plist.c
index 72c3e98..0fcd926 100644
--- a/src/plist.c
+++ b/src/plist.c
@@ -43,6 +43,7 @@
43#endif 43#endif
44 44
45#include <node.h> 45#include <node.h>
46#include <node_list.h>
46#include <hashtable.h> 47#include <hashtable.h>
47#include <ptrarray.h> 48#include <ptrarray.h>
48 49
@@ -1515,44 +1516,47 @@ PLIST_API void plist_sort(plist_t plist)
1515 plist_sort((plist_t)ch); 1516 plist_sort((plist_t)ch);
1516 } 1517 }
1517 #define KEY_DATA(x) (x->data) 1518 #define KEY_DATA(x) (x->data)
1518 #define VAL_DATA(x) (x->next->data)
1519 #define VAL_COUNT(x) (x->next->count)
1520 #define VAL_CHDN(x) (x->next->children)
1521 #define NEXT_KEY(x) (x->next->next) 1519 #define NEXT_KEY(x) (x->next->next)
1522 #define NEXT_VAL(x) (NEXT_KEY(x)->next)
1523 #define NEXT_KEY_DATA(x) (NEXT_KEY(x)->data)
1524 #define NEXT_VAL_DATA(x) (NEXT_VAL(x)->data)
1525 #define NEXT_VAL_CHDN(x) (NEXT_VAL(x)->children)
1526 #define NEXT_VAL_COUNT(x) (NEXT_VAL(x)->count)
1527 #define KEY_STRVAL(x) ((plist_data_t)(KEY_DATA(x)))->strval 1520 #define KEY_STRVAL(x) ((plist_data_t)(KEY_DATA(x)))->strval
1528 #define NEXT_KEY_STRVAL(x) ((plist_data_t)(NEXT_KEY_DATA(x)))->strval
1529 int swapped = 0; 1521 int swapped = 0;
1530 do { 1522 do {
1531 swapped = 0; 1523 swapped = 0;
1532 node_t *lptr = NULL; 1524 node_t *lptr = NULL;
1533 node_t *ptr_key = node_first_child((node_t*)plist); 1525 node_t *cur_key = node_first_child((node_t*)plist);
1534 while (NEXT_KEY(ptr_key) != lptr) { 1526
1535 if (strcmp(KEY_STRVAL(ptr_key), NEXT_KEY_STRVAL(ptr_key)) > 0) { 1527 while (NEXT_KEY(cur_key) != lptr) {
1536 // backup old values 1528 node_t *next_key = NEXT_KEY(cur_key);
1537 void* key_data_tmp = KEY_DATA(ptr_key); 1529 if (strcmp(KEY_STRVAL(cur_key), KEY_STRVAL(next_key)) > 0) {
1538 void* val_data_tmp = VAL_DATA(ptr_key); 1530 node_t *cur_val = cur_key->next;
1539 struct node_list_t *val_chdn_tmp = VAL_CHDN(ptr_key); 1531 node_t *next_val = next_key->next;
1540 unsigned int val_count_tmp = VAL_COUNT(ptr_key); 1532 // we need to swap 2 consecutive nodes with the 2 after them
1541 // replace current with next 1533 // a -> b -> [c] -> [d] -> [e] -> [f] -> g -> h
1542 KEY_DATA(ptr_key) = NEXT_KEY_DATA(ptr_key); 1534 // cur next
1543 VAL_DATA(ptr_key) = NEXT_VAL_DATA(ptr_key); 1535 // swapped:
1544 VAL_CHDN(ptr_key) = NEXT_VAL_CHDN(ptr_key); 1536 // a -> b -> [e] -> [f] -> [c] -> [d] -> g -> h
1545 VAL_COUNT(ptr_key) = NEXT_VAL_COUNT(ptr_key); 1537 // next cur
1546 // replace next with old 1538 node_t *tmp_prev = cur_key->prev;
1547 NEXT_KEY_DATA(ptr_key) = key_data_tmp; 1539 node_t *tmp_next = next_val->next;
1548 NEXT_VAL_DATA(ptr_key) = val_data_tmp; 1540 cur_key->prev = next_val;
1549 NEXT_VAL_CHDN(ptr_key) = val_chdn_tmp; 1541 cur_val->next = tmp_next;
1550 NEXT_VAL_COUNT(ptr_key) = val_count_tmp; 1542 next_val->next = cur_key;
1543 next_key->prev = tmp_prev;
1544 if (tmp_prev) {
1545 tmp_prev->next = next_key;
1546 } else {
1547 ((node_t*)plist)->children->begin = next_key;
1548 }
1549 if (tmp_next) {
1550 tmp_next->prev = cur_val;
1551 } else {
1552 ((node_t*)plist)->children->end = cur_val;
1553 }
1554 cur_key = next_key;
1551 swapped = 1; 1555 swapped = 1;
1552 } 1556 }
1553 ptr_key = NEXT_KEY(ptr_key); 1557 cur_key = NEXT_KEY(cur_key);
1554 } 1558 }
1555 lptr = ptr_key; 1559 lptr = cur_key;
1556 } while (swapped); 1560 } while (swapped);
1557 } 1561 }
1558} 1562}