LibRegex: Fix negated class validation for nested string properties
We were incorrectly checking for negated character class when string properties appeared in nested classes. Now we track negation state in the parser and correctly reject invalid string properties in negated classes.
This commit is contained in:
parent
f3a32a0b1a
commit
ff06a4a9e5
3 changed files with 22 additions and 12 deletions
|
|
@ -1841,13 +1841,21 @@ bool ECMA262Parser::parse_character_class(ByteCode& stack, size_t& match_length_
|
|||
Vector<CompareTypeAndValuePair> compares;
|
||||
|
||||
auto uses_explicit_or_semantics = false;
|
||||
bool is_negated = false;
|
||||
if (match(TokenType::Circumflex)) {
|
||||
// Negated charclass
|
||||
consume();
|
||||
compares.empend(CompareTypeAndValuePair { CharacterCompareType::Inverse, 0 });
|
||||
uses_explicit_or_semantics = true;
|
||||
is_negated = true;
|
||||
}
|
||||
|
||||
auto previous_negated_state = m_parser_state.in_negated_character_class;
|
||||
m_parser_state.in_negated_character_class = is_negated;
|
||||
ArmedScopeGuard restore_negated_state { [&] {
|
||||
m_parser_state.in_negated_character_class = previous_negated_state;
|
||||
} };
|
||||
|
||||
// ClassContents :: [empty]
|
||||
if (match(TokenType::RightBracket)) {
|
||||
consume();
|
||||
|
|
@ -1858,12 +1866,18 @@ bool ECMA262Parser::parse_character_class(ByteCode& stack, size_t& match_length_
|
|||
}
|
||||
|
||||
// ClassContents :: [~UnicodeSetsMode] NonemptyClassRanges[?UnicodeMode]
|
||||
if (!flags.unicode_sets && !parse_nonempty_class_ranges(compares, flags))
|
||||
if (!flags.unicode_sets && !parse_nonempty_class_ranges(compares, flags)) {
|
||||
restore_negated_state.disarm();
|
||||
return false;
|
||||
}
|
||||
|
||||
// ClassContents :: [+UnicodeSetsMode] ClassSetExpression
|
||||
if (flags.unicode_sets && !parse_class_set_expression(compares))
|
||||
if (flags.unicode_sets && !parse_class_set_expression(compares)) {
|
||||
restore_negated_state.disarm();
|
||||
return false;
|
||||
}
|
||||
|
||||
restore_negated_state.disarm();
|
||||
|
||||
if (uses_explicit_or_semantics && compares.size() > 2) {
|
||||
compares.insert(1, CompareTypeAndValuePair { CharacterCompareType::Or, 0 });
|
||||
|
|
@ -2433,11 +2447,7 @@ bool ECMA262Parser::parse_class_set_operand(Vector<regex::CompareTypeAndValuePai
|
|||
strings.append(MUST(current_string.to_string()));
|
||||
consume(TokenType::RightCurly, Error::MismatchingBrace);
|
||||
|
||||
bool is_negated = any_of(compares, [](auto const& compare) {
|
||||
return compare.type == CharacterCompareType::Inverse;
|
||||
});
|
||||
|
||||
if (is_negated && any_of(strings, has_multiple_code_points)) {
|
||||
if (m_parser_state.in_negated_character_class && any_of(strings, has_multiple_code_points)) {
|
||||
set_error(Error::NegatedCharacterClassStrings);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2573,11 +2583,7 @@ bool ECMA262Parser::parse_nested_class(Vector<regex::CompareTypeAndValuePair>& c
|
|||
|
||||
auto strings = Unicode::get_property_strings(property);
|
||||
|
||||
bool is_negated = any_of(compares, [](auto const& compare) {
|
||||
return compare.type == CharacterCompareType::Inverse;
|
||||
});
|
||||
|
||||
if (is_negated && any_of(strings, has_multiple_code_points)) {
|
||||
if (m_parser_state.in_negated_character_class && any_of(strings, has_multiple_code_points)) {
|
||||
set_error(Error::NegatedCharacterClassStrings);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ protected:
|
|||
size_t named_capture_groups_count { 0 };
|
||||
size_t match_length_minimum { 0 };
|
||||
size_t repetition_mark_count { 0 };
|
||||
bool in_negated_character_class { false };
|
||||
AllOptions regex_options;
|
||||
HashMap<size_t, size_t> capture_group_minimum_lengths;
|
||||
OrderedHashMap<FlyString, Vector<NamedCaptureGroup>> named_capture_groups;
|
||||
|
|
|
|||
|
|
@ -872,6 +872,9 @@ TEST_CASE(ECMA262_unicode_sets_parser_error)
|
|||
constexpr _test tests[] {
|
||||
{ "[[]"sv, regex::Error::InvalidPattern },
|
||||
{ "[[x[]]]"sv, regex::Error::NoError }, // #23691, should not crash on empty charclass within AndOr.
|
||||
{ "[[^\\u0430-\\u044f][\\p{RGI_Emoji}]]"sv, regex::Error::NoError },
|
||||
{ "[^[[\\p{RGI_Emoji}]--[A-Z]]]"sv, regex::Error::NegatedCharacterClassStrings },
|
||||
{ "[^[^\\p{RGI_Emoji}]]"sv, regex::Error::NegatedCharacterClassStrings },
|
||||
};
|
||||
|
||||
for (auto test : tests) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue