From 6cd318d784515a5869b021450b0c24221e8511f2 Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sat, 17 Apr 2021 15:46:19 +0300 Subject: [PATCH] LibJS: Convert matched regex result to string in Symbol.replace This would crash on an undefined match (no match), since the matched result was assumed to be a string (such as on discord.com). The spec suggests converting it to a string as well: https://tc39.es/ecma262/#sec-regexp.prototype-@@replace (14#c) --- Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp | 10 +++++++--- .../Tests/builtins/RegExp/RegExp.prototype.exec.js | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp index eb3047f9542..f81c995e75b 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -346,7 +346,11 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_replace) size_t result_length = length_of_array_like(global_object, result); size_t n_captures = result_length == 0 ? 0 : result_length - 1; - auto matched = result.get(0).value_or(js_undefined()); + auto matched_value = result.get(0).value_or(js_undefined()); + if (vm.exception()) + return {}; + + auto matched = matched_value.to_string(global_object); if (vm.exception()) return {}; @@ -387,7 +391,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_replace) if (replace_value.is_function()) { MarkedValueList replacer_args(vm.heap()); - replacer_args.append(matched); + replacer_args.append(js_string(vm, matched)); replacer_args.append(move(captures)); replacer_args.append(Value(position)); replacer_args.append(js_string(vm, string)); @@ -416,7 +420,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_replace) builder.append(replacement); accumulated_result = builder.build(); - next_source_position = position + matched.as_string().string().length(); + next_source_position = position + matched.length(); } } diff --git a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.exec.js b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.exec.js index e8185563378..182ecee457a 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.exec.js +++ b/Userland/Libraries/LibJS/Tests/builtins/RegExp/RegExp.prototype.exec.js @@ -148,3 +148,10 @@ test("empty character class semantics", () => { expect(res.length).toBe(1); expect(res[0]).toBe("x"); }); + +// #6409 +test("undefined match result", () => { + const r = /foo/; + r.exec = () => ({}); + expect(r[Symbol.replace]()).toBe("undefined"); +});