<feed xmlns='http://www.w3.org/2005/Atom'>
<title>libplist/src/xplist.c, branch 2.8.1</title>
<subtitle>Library to handle Apple Property List format files in binary or XML</subtitle>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/'/>
<entry>
<title>Fix leaks and crashes on allocation failure</title>
<updated>2026-11-05T11:02:05+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-11-05T11:02:05+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=9fd3406baec5997d386cdb4c7492117604ba0a70'/>
<id>9fd3406baec5997d386cdb4c7492117604ba0a70</id>
<content type='text'>
Found by failing each allocation in turn under ASan/UBSan/LSan:

- plist_free() leaked the whole tree if its work stack could not be
  allocated; free the children iteratively without extra memory
- plist_copy(): when a shallow copy of a dict/array failed, the original's
  lookup table was freed along with the copy's data (use-after-free)
- bplist parser: fix a NULL dereference in parse_date_node(), check the
  node_attach() results, and don't leak on failure; plist_to_bin() no
  longer leaks on an allocation failure
- free the plist data when node creation fails (plist constructors, XML,
  JSON and binary parsers)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Found by failing each allocation in turn under ASan/UBSan/LSan:

- plist_free() leaked the whole tree if its work stack could not be
  allocated; free the children iteratively without extra memory
- plist_copy(): when a shallow copy of a dict/array failed, the original's
  lookup table was freed along with the copy's data (use-after-free)
- bplist parser: fix a NULL dereference in parse_date_node(), check the
  node_attach() results, and don't leak on failure; plist_to_bin() no
  longer leaks on an allocation failure
- free the plist data when node creation fails (plist constructors, XML,
  JSON and binary parsers)
</pre>
</div>
</content>
</entry>
<entry>
<title>Harden allocation failure handling and size arithmetic</title>
<updated>2026-11-05T11:01:59+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-11-05T11:01:59+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=4dc93bc274867b42aa82fc91ee4d5878d23a3f36'/>
<id>4dc93bc274867b42aa82fc91ee4d5878d23a3f36</id>
<content type='text'>
- check malloc/calloc/realloc results in constructors, the JSON and
  OpenStep writers, the XML text-part helpers and base64 decoding, and
  return PLIST_ERR_NO_MEM instead of asserting or dereferencing NULL
- guard size calculations against overflow in the UTF-8/UTF-16BE
  conversions, ptrarray, and bytearray
- make hash_table_insert() report failure instead of silently dropping
  the entry; writers propagate PLIST_ERR_NO_MEM, and dict lookup caches
  are discarded so lookups fall back to a linear search
- don't overwrite an earlier parse error code in the XML parser, and
  report PLIST_ERR_NO_MEM when reading text content fails for lack of memory
- OpenStep parser: check node/data/string allocations and dict/array
  insertion results

Based on #323 by bg0d-droid.

Co-authored-by: bg0d-droid &lt;81825610+bg0d-droid@users.noreply.github.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
- check malloc/calloc/realloc results in constructors, the JSON and
  OpenStep writers, the XML text-part helpers and base64 decoding, and
  return PLIST_ERR_NO_MEM instead of asserting or dereferencing NULL
- guard size calculations against overflow in the UTF-8/UTF-16BE
  conversions, ptrarray, and bytearray
- make hash_table_insert() report failure instead of silently dropping
  the entry; writers propagate PLIST_ERR_NO_MEM, and dict lookup caches
  are discarded so lookups fall back to a linear search
- don't overwrite an earlier parse error code in the XML parser, and
  report PLIST_ERR_NO_MEM when reading text content fails for lack of memory
- OpenStep parser: check node/data/string allocations and dict/array
  insertion results

Based on #323 by bg0d-droid.

Co-authored-by: bg0d-droid &lt;81825610+bg0d-droid@users.noreply.github.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>xplist: fix double-free in node_from_xml() error paths</title>
<updated>2026-11-05T10:59:00+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-11-05T09:44:41+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=f252f243f9774b2b830172b49aa340d6994d8081'/>
<id>f252f243f9774b2b830172b49aa340d6994d8081</id>
<content type='text'>
node_from_xml() hands a freshly created node over to the tree (as
root, or by adding it to a dict/array parent), but only reset `subnode`
at the very end of the block. If an error occurred in between, e.g. the
allocation of the node path item failing right after the root node was
assigned to *plist, err_out freed the node while the tree still
referenced it, and plist_free(*plist) then freed it a second time.

Clear `subnode` right after the node has been successfully attached so
that err_out can never free a node owned by the tree. Also report
PLIST_ERR_NO_MEM instead of PLIST_ERR_PARSE when allocating the node
path item fails.

Co-authored-by: bg0d-droid &lt;81825610+bg0d-droid@users.noreply.github.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
node_from_xml() hands a freshly created node over to the tree (as
root, or by adding it to a dict/array parent), but only reset `subnode`
at the very end of the block. If an error occurred in between, e.g. the
allocation of the node path item failing right after the root node was
assigned to *plist, err_out freed the node while the tree still
referenced it, and plist_free(*plist) then freed it a second time.

Clear `subnode` right after the node has been successfully attached so
that err_out can never free a node owned by the tree. Also report
PLIST_ERR_NO_MEM instead of PLIST_ERR_PARSE when allocating the node
path item fails.

Co-authored-by: bg0d-droid &lt;81825610+bg0d-droid@users.noreply.github.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>xplist: fix memory leak when adding a node to its parent fails</title>
<updated>2026-11-05T08:39:06+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-11-05T08:39:06+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=621886ffc072699a530530fe544f828b9b2a8ef8'/>
<id>621886ffc072699a530530fe544f828b9b2a8ef8</id>
<content type='text'>
node_from_xml() ignored the return values of plist_dict_set_item() and
plist_array_append_item(). When the insertion failed (e.g. when the
nesting depth limit is hit in node_attach()), the newly created node was
never attached, yet subnode was reset to NULL, so the node, its data and
its string value were leaked.

Check the return values and bail out with PLIST_ERR_PARSE so that the
unattached node is freed in the error path.

Credit to OSSFuzz
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
node_from_xml() ignored the return values of plist_dict_set_item() and
plist_array_append_item(). When the insertion failed (e.g. when the
nesting depth limit is hit in node_attach()), the newly created node was
never attached, yet subnode was reset to NULL, so the node, its data and
its string value were leaked.

Check the return values and bail out with PLIST_ERR_PARSE so that the
unattached node is freed in the error path.

Credit to OSSFuzz
</pre>
</div>
</content>
</entry>
<entry>
<title>bytearray: Handle realloc() failure in byte_array_grow()</title>
<updated>2026-09-29T14:39:28+00:00</updated>
<author>
<name>Comtea04</name>
</author>
<published>2026-09-27T06:06:22+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=f168c10b52325b00da6355989a18a11743b33f89'/>
<id>f168c10b52325b00da6355989a18a11743b33f89</id>
<content type='text'>
byte_array_grow() assigned the result of realloc() directly to
ba-&gt;data and increased the capacity even if realloc() failed, so the
following memcpy() in byte_array_append() wrote to NULL + len.

On failure, free the old buffer and leave the byte array in a failed
state (data == NULL), which byte_array_append() already ignores. The
callers check for that state:

- the writers (bin, xml, json, openstep and the text output formats)
  return PLIST_ERR_NO_MEM instead of handing out a NULL/truncated buffer
- node_to_xml() base64-encodes &lt;data&gt; directly into the grown buffer,
  so it must bail out there (only guarded by assert() before)
- the OpenStep parser returns PLIST_ERR_NO_MEM for &lt;hex data&gt; instead of
  silently returning truncated data

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
byte_array_grow() assigned the result of realloc() directly to
ba-&gt;data and increased the capacity even if realloc() failed, so the
following memcpy() in byte_array_append() wrote to NULL + len.

On failure, free the old buffer and leave the byte array in a failed
state (data == NULL), which byte_array_append() already ignores. The
callers check for that state:

- the writers (bin, xml, json, openstep and the text output formats)
  return PLIST_ERR_NO_MEM instead of handing out a NULL/truncated buffer
- node_to_xml() base64-encodes &lt;data&gt; directly into the grown buffer,
  so it must bail out there (only guarded by assert() before)
- the OpenStep parser returns PLIST_ERR_NO_MEM for &lt;hex data&gt; instead of
  silently returning truncated data

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Print debug error message when encoutering invalid PLIST_DATE values</title>
<updated>2026-05-22T18:41:23+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-05-22T18:41:23+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=bd851a87ec93db2516455e982f121389a86fc0f7'/>
<id>bd851a87ec93db2516455e982f121389a86fc0f7</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>common: validate PLIST_DATE values before Time64_T conversion</title>
<updated>2026-05-22T17:20:51+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-05-22T17:20:51+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=ba82092e43d4769dbc6f0557d58a243f93542486'/>
<id>ba82092e43d4769dbc6f0557d58a243f93542486</id>
<content type='text'>
Avoid undefined behavior when serializing malformed PLIST_DATE values
containing NaN, infinity, or values outside the Time64_T range. Add a
shared helper for checked date conversion and use it across writer paths.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Avoid undefined behavior when serializing malformed PLIST_DATE values
containing NaN, infinity, or values outside the Time64_T range. Add a
shared helper for checked date conversion and use it across writer paths.
</pre>
</div>
</content>
</entry>
<entry>
<title>refactor: centralize formatting helpers and harden out-plutil</title>
<updated>2026-05-22T16:46:02+00:00</updated>
<author>
<name>Nikias Bassen</name>
</author>
<published>2026-05-22T16:46:02+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=9711459dbed7d60bb00c7d2c052623e8489c88e1'/>
<id>9711459dbed7d60bb00c7d2c052623e8489c88e1</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>xplist: Enforce single root value inside &lt;plist&gt;</title>
<updated>2026-02-25T01:27:00+00:00</updated>
<author>
<name>Sami Kortelainen</name>
</author>
<published>2026-02-25T01:27:00+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=6e03a1df6d1aa87c8f9e2b35f1a2ca60feca1c0e'/>
<id>6e03a1df6d1aa87c8f9e2b35f1a2ca60feca1c0e</id>
<content type='text'>
Ensure that XML property lists contain exactly one root value inside the &lt;plist&gt; element and reject any additional value nodes before &lt;/plist&gt;.

Add tests covering root value handling and nested CF$UID conversion behavior.

Co-authored-by: Sami Kortelainen &lt;sami.kortelainen@piceasoft.com&gt;
Co-authored-by: Nikias Bassen &lt;nikias@gmx.li&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Ensure that XML property lists contain exactly one root value inside the &lt;plist&gt; element and reject any additional value nodes before &lt;/plist&gt;.

Add tests covering root value handling and nested CF$UID conversion behavior.

Co-authored-by: Sami Kortelainen &lt;sami.kortelainen@piceasoft.com&gt;
Co-authored-by: Nikias Bassen &lt;nikias@gmx.li&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>xplist: Convert nested {CF$UID:&lt;int&gt;} dicts to PLIST_UID safely</title>
<updated>2026-02-22T02:39:54+00:00</updated>
<author>
<name>Sami Kortelainen</name>
</author>
<published>2026-02-22T02:39:54+00:00</published>
<link rel='alternate' type='text/html' href='https://cgit.sukimashita.com/libplist.git/commit/?id=f5e74fc1e007b8f625d91e40c160785580de8f60'/>
<id>f5e74fc1e007b8f625d91e40c160785580de8f60</id>
<content type='text'>
Convert single-entry { "CF$UID" : &lt;integer&gt; } 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 &lt;sami.kortelainen@piceasoft.com&gt;
Co-authored-by: Nikias Bassen &lt;nikias@gmx.li&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Convert single-entry { "CF$UID" : &lt;integer&gt; } 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 &lt;sami.kortelainen@piceasoft.com&gt;
Co-authored-by: Nikias Bassen &lt;nikias@gmx.li&gt;
</pre>
</div>
</content>
</entry>
</feed>
