LibRegex: Fix crash when parse result exceeds max cache size

Before, If the cache was empty we would try and evict non-existant
entries and crash. So the fix is to make sure that we don't saturate
the cache with a single parse result.
This commit is contained in:
Jess 2025-04-05 01:38:32 +13:00 committed by Ali Mohammad Pur
parent 99df80f81e
commit 83e46b3728
Notes: github-actions[bot] 2025-04-04 14:11:28 +00:00
2 changed files with 21 additions and 6 deletions

View file

@ -77,3 +77,7 @@ test("v flag should enable unicode mode", () => {
const re = new RegExp("a\\u{10FFFF}", "v");
expect(re.test("a\u{10FFFF}")).toBe(true);
});
test("parsing a large bytestring shouldn't crash", () => {
RegExp(new Uint8Array(0x40000));
});

View file

@ -48,6 +48,20 @@ static size_t s_cached_bytecode_size = 0;
static constexpr auto MaxRegexCachedBytecodeSize = 1 * MiB;
template<class Parser>
static void cache_parse_result(regex::Parser::Result const& result, CacheKey<Parser> const& key)
{
auto bytecode_size = result.bytecode.size() * sizeof(ByteCodeValueType);
if (bytecode_size > MaxRegexCachedBytecodeSize)
return;
while (bytecode_size + s_cached_bytecode_size<Parser> > MaxRegexCachedBytecodeSize)
s_cached_bytecode_size<Parser> -= s_parser_cache<Parser>.take_first().bytecode.size() * sizeof(ByteCodeValueType);
s_parser_cache<Parser>.set(key, result);
s_cached_bytecode_size<Parser> += bytecode_size;
}
template<class Parser>
Regex<Parser>::Regex(ByteString pattern, typename ParserTraits<Parser>::OptionsType regex_options)
: pattern_value(move(pattern))
@ -61,12 +75,9 @@ Regex<Parser>::Regex(ByteString pattern, typename ParserTraits<Parser>::OptionsT
parser_result = parser.parse();
run_optimization_passes();
if (parser_result.error == regex::Error::NoError) {
while (parser_result.bytecode.size() * sizeof(ByteCodeValueType) + s_cached_bytecode_size<Parser> > MaxRegexCachedBytecodeSize)
s_cached_bytecode_size<Parser> -= s_parser_cache<Parser>.take_first().bytecode.size() * sizeof(ByteCodeValueType);
s_parser_cache<Parser>.set({ pattern_value, regex_options }, parser_result);
s_cached_bytecode_size<Parser> += parser_result.bytecode.size() * sizeof(ByteCodeValueType);
}
if (parser_result.error == regex::Error::NoError)
cache_parse_result<Parser>(parser_result, { pattern_value, regex_options });
}
if (parser_result.error == regex::Error::NoError)