#5535·boa

RegExp.prototype.source double-escapes an already escaped `/`

Author: regularkevvvCreated Sep 19, 2026Updated Sep 19, 2026

Describe the bug

RegExp.prototype.source escapes a / that the pattern has already escaped, so /a\/b/.source returns a\\/b instead of a\/b.

That is a different regex (an escaped backslash followed by /), so a regex built again from its own source no longer behaves like the original.

To Reproduce

cargo run --bin boa -- -e 'console.log(/a\/b/.source)'
  • Expected: a\/b
  • Actual: a\\/b

Building the regex again from its source stops matching:

cargo run --bin boa -- -e 'const re = /a\/b/; console.log(new RegExp(re.source).test("a/b"))'
  • Expected: true
  • Actual: false

The same happens with a backslash followed by a line terminator:

cargo run --bin boa -- -e 'console.log(new RegExp("\\\n").source)'
  • Expected: \n
  • Actual: \\n

Expected behavior

Per EscapeRegExpPattern, the returned string, evaluated again as a regex with the same flags, must behave identically to the original. / and line terminators that are already escaped should be left as they are. V8 returns a\/b.

Build environment (please complete the following information):

  • OS: macOS
  • Version: 26.6.2
  • Target triple: aarch64-apple-darwin
  • Rustc version: rustc 1.98.0 (88d9e12ae 2026-08-18)

Additional context

Reproduced on main at 3046147f. The cause is escape_pattern in core/engine/src/builtins/regexp/mod.rs, which adds a \ before every / without checking whether it is already preceded by an unescaped backslash.

This also makes two test262 tests fail: test/staging/sm/RegExp/source.js and test/staging/sm/RegExp/toString.js.

I have a fix ready and will open a PR for it.