diff --git a/Libraries/LibJS/Tests/builtins/RegExp/RegExp.js b/Libraries/LibJS/Tests/builtins/RegExp/RegExp.js index f921f1959af..51e4471b490 100644 --- a/Libraries/LibJS/Tests/builtins/RegExp/RegExp.js +++ b/Libraries/LibJS/Tests/builtins/RegExp/RegExp.js @@ -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)); +}); diff --git a/Libraries/LibRegex/RegexMatcher.cpp b/Libraries/LibRegex/RegexMatcher.cpp index 37125d1fa7e..12731612641 100644 --- a/Libraries/LibRegex/RegexMatcher.cpp +++ b/Libraries/LibRegex/RegexMatcher.cpp @@ -48,6 +48,20 @@ static size_t s_cached_bytecode_size = 0; static constexpr auto MaxRegexCachedBytecodeSize = 1 * MiB; +template +static void cache_parse_result(regex::Parser::Result const& result, CacheKey const& key) +{ + auto bytecode_size = result.bytecode.size() * sizeof(ByteCodeValueType); + if (bytecode_size > MaxRegexCachedBytecodeSize) + return; + + while (bytecode_size + s_cached_bytecode_size > MaxRegexCachedBytecodeSize) + s_cached_bytecode_size -= s_parser_cache.take_first().bytecode.size() * sizeof(ByteCodeValueType); + + s_parser_cache.set(key, result); + s_cached_bytecode_size += bytecode_size; +} + template Regex::Regex(ByteString pattern, typename ParserTraits::OptionsType regex_options) : pattern_value(move(pattern)) @@ -61,12 +75,9 @@ Regex::Regex(ByteString pattern, typename ParserTraits::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 > MaxRegexCachedBytecodeSize) - s_cached_bytecode_size -= s_parser_cache.take_first().bytecode.size() * sizeof(ByteCodeValueType); - s_parser_cache.set({ pattern_value, regex_options }, parser_result); - s_cached_bytecode_size += parser_result.bytecode.size() * sizeof(ByteCodeValueType); - } + + if (parser_result.error == regex::Error::NoError) + cache_parse_result(parser_result, { pattern_value, regex_options }); } if (parser_result.error == regex::Error::NoError)