From c68e4a0eee1f94ad538d6e86086782485c54bbdf Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Thu, 16 Jul 2026 18:48:36 +0300 Subject: [PATCH] Size entity attribute storage to schema arity, not token count When a STEP instance has fewer attribute tokens than its schema declares (commonly from corrupted/malformed syntax), parse_context::construct() sized the in-memory attribute storage to the smaller token count instead of the schema's attribute count. This left the storage's last N attribute slots simply nonexistent rather than blank, so any later read of one of those trailing attributes by index threw an uncaught IfcParse::IfcException ("Index N is out of range for storage of size N") that terminated the whole process (SIGABRT) instead of being handled as a parse warning. Fix: when the schema declaration is known, size the storage to the schema's attribute count. Indices beyond the number of tokens found are left at their existing default-constructed blank value (the storage constructor already blank-initializes every slot), so a truncated instance now degrades to blank values for its missing trailing attributes, matching the parser's existing "expected N attribute values, found M" warning intent instead of crashing. Reproduced with the fuzzing script attached to #5679: single-byte mutations of a minimal IFC4 file that corrupt the IFCPROJECT instance's token stream reliably aborted IfcConvert with this exact exception before the fix, and now parse with a logged syntax error and exit code 0. Fixes #5679 Generated with the assistance of an AI coding tool. --- src/ifcparse/IfcFile.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ifcparse/IfcFile.cpp b/src/ifcparse/IfcFile.cpp index 9f938ad41d..050279fde8 100644 --- a/src/ifcparse/IfcFile.cpp +++ b/src/ifcparse/IfcFile.cpp @@ -273,9 +273,18 @@ IfcEntityInstanceData IfcParse::parse_context::construct(boost::optional return IfcEntityInstanceData(in_memory_attribute_storage(0)); } + // When the schema declaration is known, size the storage to the schema's + // attribute count rather than the (possibly smaller) number of tokens + // actually found. Attributes are only assigned for indices covered by + // tokens_ below; any remaining trailing indices stay at their + // default-constructed blank value. This keeps every instance's storage + // consistent with its schema arity, so that a malformed/truncated + // instance (e.g. corrupted STEP syntax dropping a trailing attribute) + // degrades to a blank value for the missing attribute instead of an + // out-of-range access when that attribute is later read by index. in_memory_attribute_storage storage(coerce_attribute_count ? (decl != nullptr - ? (std::min)(parameter_types.size(), tokens_.size()) + ? parameter_types.size() : tokens_.size()) : tokens_.size() );