diff options
| author | 2026-02-22 03:39:54 +0100 | |
|---|---|---|
| committer | 2026-02-22 03:39:54 +0100 | |
| commit | f5e74fc1e007b8f625d91e40c160785580de8f60 (patch) | |
| tree | ce9da2c80c13a0718605019c098e2a3b775b814a /src/xplist.c | |
| parent | 3bdee70a9c1490ea011c6fb65193b2c7e242d26d (diff) | |
| download | libplist-f5e74fc1e007b8f625d91e40c160785580de8f60.tar.gz libplist-f5e74fc1e007b8f625d91e40c160785580de8f60.tar.bz2 | |
xplist: Convert nested {CF$UID:<int>} dicts to PLIST_UID safely
Convert single-entry { "CF$UID" : <integer> } dictionaries to PLIST_UID
nodes when closing a dict in the XML parser.
Refactor node cleanup logic:
- Split plist_free_data() into internal _plist_free_data()
- Introduce plist_free_children() to release child nodes separately
- Update plist_set_element_val() to free children before changing
container node types
- Ensure PLIST_DICT hashtables do not free values (assert + force
free_func = NULL)
This avoids in-place container mutation issues and ensures child
nodes and container metadata are released correctly before
changing node type.
Co-authored-by: Sami Kortelainen <sami.kortelainen@piceasoft.com>
Co-authored-by: Nikias Bassen <nikias@gmx.li>
Diffstat (limited to 'src/xplist.c')
| -rw-r--r-- | src/xplist.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/src/xplist.c b/src/xplist.c index 73e2b9f..a445dc5 100644 --- a/src/xplist.c +++ b/src/xplist.c | |||
| @@ -1562,6 +1562,26 @@ handle_closing: | |||
| 1562 | ctx->err = PLIST_ERR_PARSE; | 1562 | ctx->err = PLIST_ERR_PARSE; |
| 1563 | goto err_out; | 1563 | goto err_out; |
| 1564 | } | 1564 | } |
| 1565 | |||
| 1566 | /* When closing a dictionary, convert a single-entry | ||
| 1567 | { "CF$UID" : <integer> } dictionary into a PLIST_UID node. | ||
| 1568 | Perform the conversion before moving to the parent node. */ | ||
| 1569 | if (!strcmp(node_path->type, XPLIST_DICT) && parent && plist_get_node_type(parent) == PLIST_DICT) { | ||
| 1570 | if (plist_dict_get_size(parent) == 1) { | ||
| 1571 | plist_t uid = plist_dict_get_item(parent, "CF$UID"); | ||
| 1572 | if (uid) { | ||
| 1573 | uint64_t val = 0; | ||
| 1574 | if (plist_get_node_type(uid) != PLIST_INT) { | ||
| 1575 | ctx->err = PLIST_ERR_PARSE; | ||
| 1576 | PLIST_XML_ERR("Invalid node type for CF$UID dict entry (must be PLIST_INT)\n"); | ||
| 1577 | goto err_out; | ||
| 1578 | } | ||
| 1579 | plist_get_uint_val(uid, &val); | ||
| 1580 | plist_set_uid_val(parent, val); | ||
| 1581 | } | ||
| 1582 | } | ||
| 1583 | } | ||
| 1584 | |||
| 1565 | if (depth > 0) depth--; | 1585 | if (depth > 0) depth--; |
| 1566 | struct node_path_item *path_item = node_path; | 1586 | struct node_path_item *path_item = node_path; |
| 1567 | node_path = (struct node_path_item*)node_path->prev; | 1587 | node_path = (struct node_path_item*)node_path->prev; |
