Skip to content

fix(string): replace/replaceAll detect a RegExp searchValue at runtime (#4871)#5053

Merged
proggeramlug merged 1 commit into
mainfrom
fix/replace-regex-from-property
Jun 13, 2026
Merged

fix(string): replace/replaceAll detect a RegExp searchValue at runtime (#4871)#5053
proggeramlug merged 1 commit into
mainfrom
fix/replace-regex-from-property

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Fixes #4871.

Root cause

In lower_string_method.rs, needle_is_regex is a static test: RegExp literal or RegExp-typed local. A RegExp read from an object property (obj.regex) or destructured in a for...of is neither, so the lowering fell into the js_string_coerce(needle) arm — the RegExp was stringified to "/foo/g" and searched literally. No match → input returned unchanged, silently (the issue's PII-redaction table did zero replacements).

Fix

  • New runtime dispatchers js_string_replace_search_dyn / js_string_replace_all_search_dyn (regex/replace_fn.rs): probe the needle against the registered-RegExp set (handles NaN-boxed and raw-I64 module-slot pointers), route to the regex _dyn path on hit, ToString-coerce on miss — preserving spec coercion order (searchValue before replaceValue) and every replacement shape (string, $-templates, named groups, function replacer) via the existing _dyn family.
  • Codegen routes every statically-untyped searchValue through them. Statically-known regex/string needles keep their direct fast paths.

Validation

10-case e2e matches node --experimental-strip-types byte-for-byte: all four issue-table forms, replaceAll from property, function replacer over a destructured pattern table, non-regex dynamic needles (string-prop, number) still coerce, $1 backrefs and $<name> named groups through property regexes. Dynamic (any-typed) receivers verified separately.

  • New unit test search_dyn_dispatches_runtime_regex_and_coerces_non_regex; replace (10) and regex (21) unit-test groups pass; string-semantics / key-order / spec-throws gap tests diff clean vs Node.

Code-only PR — version bump + changelog left for merge time.

#4871)

Codegen's needle_is_regex detection covers RegExp literals and
RegExp-typed locals only. A RegExp read from an object property (or
destructured in a for...of) lowered as an opaque value and was
ToString-coerced — str.replace(obj.regex, …) literally searched for
"/foo/g" and silently returned the input unchanged (surfaced as a
PII-redaction pass that did nothing in the native binary).

Add js_string_replace_search_dyn / js_string_replace_all_search_dyn,
which probe the registered-RegExp set before coercing and defer to the
existing _dyn replacement-shape dispatchers; route every statically
untyped searchValue through them. Statically known regex/string needles
keep their existing direct paths.
@proggeramlug proggeramlug merged commit 7258551 into main Jun 13, 2026
13 checks passed
@proggeramlug proggeramlug deleted the fix/replace-regex-from-property branch June 13, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

String.prototype.replace ignores a RegExp read from an object property (native compile) — returns input unchanged

1 participant