From 573d8bb05587dafa90124f003dae66ada3a6b4a7 Mon Sep 17 00:00:00 2001 From: Mike German Date: Mon, 6 Jul 2026 22:49:48 -0400 Subject: [PATCH] Fix data corruption from unrecognized entity in StrPair::GetStr() When an unrecognized entity (e.g. &bogus;) follows a recognized entity that was expanded to a shorter string, the write pointer q lags behind the read pointer p. The unrecognized-entity branch advanced both pointers without writing *q, so a stale buffer byte replaced the '&' in the output (e.g. "&&bogus;" parsed to "&abogus;" instead of "&&bogus;"). Copy *p to *q before advancing, matching the numeric character-reference fallback a few lines above. Adds a focused xmltest assertion. Fixes #1082. Signed-off-by: Mike German --- tinyxml2.cpp | 5 +++++ xmltest.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/tinyxml2.cpp b/tinyxml2.cpp index 69d93ef0..b150a374 100644 --- a/tinyxml2.cpp +++ b/tinyxml2.cpp @@ -347,6 +347,11 @@ const char* StrPair::GetStr() } if ( !entityFound ) { // fixme: treat as error? + // Not a recognized entity: copy the '&' through + // verbatim. The write pointer 'q' can lag behind the + // read pointer 'p' after an earlier entity expansion, + // so '*q' must be assigned or a stale byte is emitted. + *q = *p; ++p; ++q; } diff --git a/xmltest.cpp b/xmltest.cpp index db9df56c..c09ff2ca 100644 --- a/xmltest.cpp +++ b/xmltest.cpp @@ -1203,6 +1203,18 @@ int main( int argc, const char ** argv ) } } + { + // An unrecognized entity following a recognized (expanded) entity must + // not corrupt the '&'. After "&" is collapsed the write pointer lags + // the read pointer, and the following "&bogus;" used to emit a stale + // buffer byte in place of the '&'. See issue #1082. + XMLDocument doc; + doc.Parse( "&&bogus;" ); + XMLTest( "Unrecognized entity after expansion: parse", false, doc.Error() ); + XMLTest( "Unrecognized entity after expansion: text", + "&&bogus;", doc.FirstChildElement( "a" )->GetText() ); + } + { // Suppress entities. const char* passages =