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.
This commit is contained in:
Petru Conduraru
2026-07-16 18:48:36 +03:00
committed by Thomas Krijnen
parent 6603c8459a
commit c68e4a0eee
+10 -1
View File
@@ -273,9 +273,18 @@ IfcEntityInstanceData IfcParse::parse_context::construct(boost::optional<size_t>
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()
);