Don't strip trailing null byte from binary records in Altium parser

ReadProperties() unconditionally stripped a trailing 0x00 byte from all
records. This is correct for text records where 0x00 is a string
terminator, but binary records contain raw compressed data where 0x00 is
valid payload. When a zlib stream happened to end with 0x00, stripping
it caused ReadFullPascalString() to throw out_of_range, crashing Altium
.SchLib imports.

Only strip the null byte for non-binary records.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23013
This commit is contained in:
Seth Hillbrand
2026-02-11 10:05:40 -08:00
parent e1e00acccb
commit 9dbffdffeb
2 changed files with 37 additions and 1 deletions
+1 -1
View File
@@ -382,7 +382,7 @@ std::map<wxString, wxString> ALTIUM_BINARY_PARSER::ReadProperties(
// we use std::string because std::string can handle NULL-bytes
// wxString would end the string at the first NULL-byte
std::string str = std::string( m_pos, length - ( hasNullByte ? 1 : 0 ) );
std::string str = std::string( m_pos, length - ( ( hasNullByte && !isBinary ) ? 1 : 0 ) );
m_pos += length;
if( isBinary )
@@ -286,4 +286,40 @@ BOOST_DATA_TEST_CASE( ReadProperties,
}
/**
* Verify that binary records ending with 0x00 are not truncated.
* Regression test for https://gitlab.com/kicad/code/kicad/-/issues/23013
*/
BOOST_AUTO_TEST_CASE( ReadPropertiesBinaryNullBytePreserved )
{
// Simulate a binary record whose payload ends with 0x00.
// The MSB of the 4-byte length field flags the record as binary.
const char binaryPayload[] = { 0x01, 0x02, 0x03, 0x00 };
const uint32_t payloadLen = sizeof( binaryPayload );
const uint32_t lengthField = payloadLen | 0x01000000;
size_t totalSize = 4 + payloadLen;
std::unique_ptr<char[]> content = std::make_unique<char[]>( totalSize );
std::memcpy( content.get(), &lengthField, 4 );
std::memcpy( content.get() + 4, binaryPayload, payloadLen );
ALTIUM_BINARY_PARSER parser( content, totalSize );
std::string receivedData;
auto binaryHandler = [&]( const std::string& aData ) -> std::map<wxString, wxString>
{
receivedData = aData;
return {};
};
parser.ReadProperties( binaryHandler );
BOOST_CHECK_EQUAL( parser.HasParsingError(), false );
BOOST_CHECK_EQUAL( parser.GetRemainingBytes(), 0 );
BOOST_CHECK_EQUAL( receivedData.size(), payloadLen );
BOOST_CHECK_EQUAL( receivedData.back(), '\0' );
}
BOOST_AUTO_TEST_SUITE_END()