src/lib/VSDXParser.cpp | 4 ++-- src/test/Makefile.am | 3 ++- src/test/data/tab-short-prefix.vsdx |binary src/test/importtest.cpp | 21 +++++++++++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-)
New commits: commit 724c22ee8a999293bf13838e72923b001ae5b352 Author: Caolán McNamara <[email protected]> AuthorDate: Fri May 22 12:50:19 2026 +0000 Commit: Caolán McNamara <[email protected]> CommitDate: Fri May 22 14:53:36 2026 +0200 keep inside buffer readTabRow on short N attribute Guard the pointer arithmetic on xmlStrlen first. Change-Id: I8d400bc287a77235f3ac497e4afac88169034a6b Reviewed-on: https://gerrit.libreoffice.org/c/libvisio/+/205556 Reviewed-by: Caolán McNamara <[email protected]> Tested-by: Caolán McNamara <[email protected]> diff --git a/src/lib/VSDXParser.cpp b/src/lib/VSDXParser.cpp index ba977ad..4265843 100644 --- a/src/lib/VSDXParser.cpp +++ b/src/lib/VSDXParser.cpp @@ -1455,7 +1455,7 @@ void libvisio::VSDXParser::readTabRow(xmlTextReaderPtr reader) if (XML_READER_TYPE_ELEMENT == tokenType) { const std::shared_ptr<xmlChar> stringValue(xmlTextReaderGetAttribute(reader, BAD_CAST("N")), xmlFree); - if (stringValue) + if (stringValue && xmlStrlen(stringValue.get()) > 8) { unsigned idx = xmlStringToLong(stringValue.get()+8); ret = readDoubleData((*m_currentTabSet)[idx].m_position, reader); @@ -1466,7 +1466,7 @@ void libvisio::VSDXParser::readTabRow(xmlTextReaderPtr reader) if (XML_READER_TYPE_ELEMENT == tokenType) { const std::shared_ptr<xmlChar> stringValue(xmlTextReaderGetAttribute(reader, BAD_CAST("N")), xmlFree); - if (stringValue) + if (stringValue && xmlStrlen(stringValue.get()) > 9) { unsigned idx = xmlStringToLong(stringValue.get()+9); ret = readByteData((*m_currentTabSet)[idx].m_alignment, reader); diff --git a/src/test/Makefile.am b/src/test/Makefile.am index 7889ede..4fc6a5d 100644 --- a/src/test/Makefile.am +++ b/src/test/Makefile.am @@ -90,7 +90,8 @@ EXTRA_DIST = \ data/testfile4.vsdx \ data/testfile5.vsdx \ data/testfile6.vsdx \ - data/recursion-cycle.vsdx + data/recursion-cycle.vsdx \ + data/tab-short-prefix.vsdx # ImportTest::testVsdMetadataTitleUtf8 checks formatted date string AM_TESTS_ENVIRONMENT = TZ=UTC; export TZ; diff --git a/src/test/data/tab-short-prefix.vsdx b/src/test/data/tab-short-prefix.vsdx new file mode 100644 index 0000000..20237f1 Binary files /dev/null and b/src/test/data/tab-short-prefix.vsdx differ diff --git a/src/test/importtest.cpp b/src/test/importtest.cpp index 4054929..5de2cf9 100644 --- a/src/test/importtest.cpp +++ b/src/test/importtest.cpp @@ -236,6 +236,7 @@ class ImportTest : public CPPUNIT_NS::TestFixture CPPUNIT_TEST(testVsdxFillStylesFromTheme6); CPPUNIT_TEST(testVsdxPageSelfReferenceCycle); + CPPUNIT_TEST(testVsdxTabRowShortPrefix); CPPUNIT_TEST_SUITE_END(); @@ -270,6 +271,7 @@ class ImportTest : public CPPUNIT_NS::TestFixture void testVsdxFillStylesFromTheme6(); void testVsdxPageSelfReferenceCycle(); + void testVsdxTabRowShortPrefix(); xmlBufferPtr m_buffer; xmlDocPtr m_doc; @@ -657,6 +659,25 @@ void ImportTest::testVsdxFillStylesFromTheme6() assertXPath(m_doc, "/document/page/layer[3]//setStyle[2]", "fill-color", "#feffff"); } +// N="X" on <Position>/<Alignment> is shorter than the "Position"/"Alignment" +// prefix the code skips with +8/+9 - must not read past the xmlChar buffer +void ImportTest::testVsdxTabRowShortPrefix() +{ + librevenge::RVNGString path(TDOC "/tab-short-prefix.vsdx"); + librevenge::RVNGFileStream input(path.cstr()); + CPPUNIT_ASSERT(libvisio::VisioDocument::isSupported(&input)); + + xmlTextWriterPtr writer = xmlNewTextWriterMemory(m_buffer, 0); + CPPUNIT_ASSERT(writer); + xmlTextWriterStartDocument(writer, 0, 0, 0); + libvisio::XmlDrawingGenerator painter(writer); + + (void)libvisio::VisioDocument::parse(&input, &painter); + + xmlTextWriterEndDocument(writer); + xmlFreeTextWriter(writer); +} + // pages.xml.rels points at pages.xml - must not recurse forever void ImportTest::testVsdxPageSelfReferenceCycle() {
