From d2381ad6c627f9629b4fa8e704164379b0786a48 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Mon, 6 Jul 2026 08:19:57 +0300 Subject: [PATCH] IfcParse: don't strip delimiters from a single-character token #5683 asStringRef removes the first and last characters of a string, enumeration or binary token to drop the delimiters, guarded only by !str.empty(). A malformed single-character token (e.g. a bare '.' left when a fuzzer turns '.PHYSICAL.' into '.)HYSICAL.') has length 1, so the first erase empties the string and the second erase(str.begin()) runs on an empty string. That is undefined behaviour: benign on a normal build, but it aborts (or throws std::length_error from a later append) under a hardened libstdc++ with _GLIBCXX_ASSERTIONS, which is why this file only segfaulted on the Fedora build. Require at least two characters before stripping. Co-Authored-By: Claude Fable 5 --- src/ifcparse/IfcParse.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 28ada453bd..52f8a686de 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -449,7 +449,14 @@ const std::string& TokenFunc::asStringRef(const Token& token) { } std::string& str = token.lexer->GetTempString(); token.lexer->TokenString(token.startPos, str); - if ((isString(token) || isEnumeration(token) || isBinary(token)) && !str.empty()) { + // A well-formed string/enumeration/binary token has both delimiters (e.g. + // '...', .XXX., "...."), so at least two characters. Malformed input from a + // fuzzer can produce a single-character token (e.g. a bare '.' left by + // ".)" instead of ".PHYSICAL."); stripping both ends would then erase past + // the end of an already-empty string, which is undefined behaviour and + // aborts under hardened standard libraries (_GLIBCXX_ASSERTIONS). Require + // two characters before stripping. See #5683. + if ((isString(token) || isEnumeration(token) || isBinary(token)) && str.size() >= 2) { //remove start+end characters in-place str.erase(str.end() - 1); str.erase(str.begin());