diff options
| author | 2023-02-05 13:42:23 +0100 | |
|---|---|---|
| committer | 2023-02-05 13:42:23 +0100 | |
| commit | 52826a6c229ed3e353d4dae711a6c52a96d99764 (patch) | |
| tree | bbff0a7bbea4e62f7646174ee245e5950b4b0d30 /src | |
| parent | 706771e357570d1bee268fc7c2233506da967bcd (diff) | |
| download | libplist-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')
| -rw-r--r-- | src/plist.c | 62 |
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 | } |
