LibJS: Use stored input for RegExp legacy static property views

The m_last_match, m_left_context, and m_right_context views were being
created from a temporary string instead of from the owned m_input.
This caused the views to point to destroyed stack memory when accessing
RegExp.lastMatch after calling String.replace() with a regex.
This commit is contained in:
aplefull
2025-12-03 00:55:55 +01:00
committed by Andreas Kling
parent ed7a86b8cc
commit e0dd182964
Notes: github-actions[bot] 2025-12-03 12:46:27 +00:00
2 changed files with 13 additions and 3 deletions

View File

@@ -94,7 +94,7 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1
legacy_static_properties.set_input(string); legacy_static_properties.set_input(string);
// 8. Set the value of Cs [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order. // 8. Set the value of Cs [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order.
auto last_match = string.substring_view(start_index, end_index - start_index); auto last_match = legacy_static_properties.input()->substring_view(start_index, end_index - start_index);
legacy_static_properties.set_last_match(last_match); legacy_static_properties.set_last_match(last_match);
// 9. If n > 0, set the value of Cs [[RegExpLastParen]] internal slot to the last element of capturedValues. // 9. If n > 0, set the value of Cs [[RegExpLastParen]] internal slot to the last element of capturedValues.
@@ -108,11 +108,11 @@ void update_legacy_regexp_static_properties(RegExpConstructor& constructor, Utf1
} }
// 11. Set the value of Cs [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order. // 11. Set the value of Cs [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order.
auto left_context = string.substring_view(0, start_index); auto left_context = legacy_static_properties.input()->substring_view(0, start_index);
legacy_static_properties.set_left_context(left_context); legacy_static_properties.set_left_context(left_context);
// 12. Set the value of Cs [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order. // 12. Set the value of Cs [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order.
auto right_context = string.substring_view(end_index, len - end_index); auto right_context = legacy_static_properties.input()->substring_view(end_index, len - end_index);
legacy_static_properties.set_right_context(right_context); legacy_static_properties.set_right_context(right_context);
// 13. For each integer i such that 1 ≤ i ≤ 9 // 13. For each integer i such that 1 ≤ i ≤ 9

View File

@@ -196,3 +196,13 @@ test("calling with no argument is the same as calling with undefined.", () => {
expect(/^undefined$/.test()).toBeTrue(); expect(/^undefined$/.test()).toBeTrue();
expect(/^undefined$/.exec()).toEqual(["undefined"]); expect(/^undefined$/.exec()).toEqual(["undefined"]);
}); });
test("legacy static properties with a temporary string", () => {
for (let i = 0; i < 10; i++) {
"a11".replace(/(a)1/g, "x");
expect(RegExp.lastMatch).toBe("a1");
expect(RegExp.leftContext).toBe("");
expect(RegExp.rightContext).toBe("1");
expect(RegExp.$1).toBe("a");
}
});