Skip to content

RegExp ^ and $ under /m recognise only \n — 46 multiline regexes in the cc bundle mis-parse CRLF input #9408

Description

@proggeramlug

#9218 fixed . to exclude all four LineTerminators. The anchors were not fixed: ^ and $ under /m still recognise only \n.

"one\rtwo".match(/^.*$/gm)      // node ["one","two"]        perry null
"a
b".match(/^.*$/gm)      // node ["a","b"]            perry null
"one\r\ntwo".match(/^.*$/gm)    // node ["one","","two"]     perry ["two"]
"one\r\ntwo".replace(/^/gm,">") // node ">one\r>\n>two"      perry ">one\r\n>two"

Per ES §22.2.2.6, ^/$ in multiline mode match at any LineTerminator: \n, \r, U+2028, U+2029 — the same set . excludes.

Reachability

A tokenizer census (not a grep) of cli_2.1.112.js found 46 /m regexes, including:

/^gitdir:\s*(.+)$/m
/^diff --git /m
/^ID=["']?(\S+?)["']?\s*$/m
/^## /gm
/^#+\s+(.+)$/m
/^[ \t]*<claude-code-hint\s+([^>]*?)\s*\/>[ \t]*$/gm
/[ \t]+$/gm

Any CRLF markdown, git output on a Windows checkout, or /etc/os-release parse silently mis-matches. A cc-level trigger reachable without the network could not be constructed, so this is reachability by static evidence rather than an end-to-end demonstration — but the divergence itself is deterministic and minimal.

Suggested fix

Wherever #9218 established the LineTerminator set for ., reuse it for the multiline anchor translation. The regression test should cover \r, \r\n (which must produce an empty match between the pair), U+2028 and U+2029, in match and replace, since \r\n is the case that most naturally comes out wrong.

Found by a differential stress-test of claude-code under perry.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions