GroupBuilder stores a std::string_view pattern that references the originating TreeRegexp::storedPattern. The current copy constructor and copy-assignment operator shallow-copy rootGroupBuilder, which means the new object's group builder tree still points into other.storedPattern rather than into this->storedPattern.
If other is destroyed (or its storedPattern is moved/mutated via copy-assignment) before the copy is used, the string_views dangle.
Fix: Rebuild the group tree from the freshly stored pattern in both the copy constructor and copy-assignment operator:
TreeRegexp::TreeRegexp(const TreeRegexp& other)
: storedPattern{ other.storedPattern }
, regexStrategy{ CreateRegexStrategy(storedPattern) }
, rootGroupBuilder{ CreateGroupBuilder(storedPattern) } // rebuild from this->storedPattern
{}
TreeRegexp& TreeRegexp::operator=(const TreeRegexp& other)
{
storedPattern = other.storedPattern;
regexStrategy = CreateRegexStrategy(storedPattern);
rootGroupBuilder = CreateGroupBuilder(storedPattern); // rebuild from this->storedPattern
return *this;
}
This mirrors what the primary constructor does and ensures all string_views point into this->storedPattern.
File: cucumber_cpp/library/cucumber_expression/TreeRegexp.cpp (lines ~191–207)
GroupBuilderstores astd::string_view patternthat references the originatingTreeRegexp::storedPattern. The current copy constructor and copy-assignment operator shallow-copyrootGroupBuilder, which means the new object's group builder tree still points intoother.storedPatternrather than intothis->storedPattern.If
otheris destroyed (or itsstoredPatternis moved/mutated via copy-assignment) before the copy is used, thestring_views dangle.Fix: Rebuild the group tree from the freshly stored pattern in both the copy constructor and copy-assignment operator:
This mirrors what the primary constructor does and ensures all
string_views point intothis->storedPattern.File:
cucumber_cpp/library/cucumber_expression/TreeRegexp.cpp(lines ~191–207)