Skip to content

Commit 9a87909

Browse files
cynarlabclaude
andcommitted
fix(dart): blank string literals with a linear scan, not a regex (CodeQL, #790)
CodeQL's polynomial-ReDoS check still flagged the disjoint form "(?:[^"\\]|\\.)*" — an unterminated literal of escaped quotes is rescanned from every inner quote. The `main(` line scan now blanks literals and cuts the `//` comment with a hand-written character loop, linear by construction; same tests, same results. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent bfd3531 commit 9a87909

1 file changed

Lines changed: 29 additions & 7 deletions

File tree

‎packages/shared/src/interfaces/adapter-policy-dart.ts‎

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,36 @@ function isAsyncGap(frame: StackFrame): boolean {
3737
/** The `main(` declaration; the VM binds a breakpoint on that line to main's first statement. */
3838
const MAIN_DECLARATION = /\bmain\s*\(/;
3939
/**
40-
* A string literal of either quote kind. The alternatives inside are disjoint (a backslash is
41-
* consumed only by the escape branch), so the match is linear in the line — CodeQL's
42-
* polynomial-ReDoS check rejects the backreference form `(["'])(?:\\.|(?!\1).)*\1`.
40+
* The line with its string literals blanked and its `//` comment cut, so `main(` inside either
41+
* does not count. A hand-written scan, linear by construction: CodeQL's polynomial-ReDoS check
42+
* rejects the regex forms (`(["'])(?:\\.|(?!\1).)*\1` and even the disjoint
43+
* `"(?:[^"\\]|\\.)*"`) on an unterminated literal full of escaped quotes.
4344
*/
44-
const STRING_LITERAL = /"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g;
45-
/** A line with its `//` comment and string literals blanked, so `main(` inside them does not count. */
46-
const codeOnly = (line: string): string =>
47-
line.replace(STRING_LITERAL, '""').replace(/\/\/.*$/, '');
45+
const codeOnly = (line: string): string => {
46+
let out = '';
47+
let quote: string | undefined;
48+
for (let i = 0; i < line.length; i++) {
49+
const ch = line[i];
50+
if (quote !== undefined) {
51+
if (ch === '\\') {
52+
i++; // the escaped character is part of the literal
53+
} else if (ch === quote) {
54+
quote = undefined;
55+
}
56+
continue;
57+
}
58+
if (ch === '"' || ch === "'") {
59+
quote = ch;
60+
out += '""';
61+
continue;
62+
}
63+
if (ch === '/' && line[i + 1] === '/') {
64+
break;
65+
}
66+
out += ch;
67+
}
68+
return out;
69+
};
4870

4971
export const DartAdapterPolicy = {
5072
name: 'dart',

0 commit comments

Comments
 (0)