Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ff03ed1

Browse filesBrowse files
aduh95danielleadams
authored andcommitted
readline: improve robustness against prototype mutation
PR-URL: #45614 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 979d837 commit ff03ed1
Copy full SHA for ff03ed1

File tree

Expand file treeCollapse file tree

1 file changed

+34
-22
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+34
-22
lines changed
Open diff view settings
Collapse file

‎lib/internal/readline/interface.js‎

Copy file name to clipboardExpand all lines: lib/internal/readline/interface.js
+34-22Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,10 @@ const {
2222
NumberIsNaN,
2323
ObjectSetPrototypeOf,
2424
RegExpPrototypeExec,
25-
RegExpPrototypeSymbolReplace,
26-
RegExpPrototypeSymbolSplit,
2725
StringPrototypeCodePointAt,
2826
StringPrototypeEndsWith,
2927
StringPrototypeRepeat,
3028
StringPrototypeSlice,
31-
StringPrototypeSplit,
3229
StringPrototypeStartsWith,
3330
StringPrototypeTrim,
3431
Symbol,
@@ -77,7 +74,7 @@ const kHistorySize = 30;
7774
const kMaxUndoRedoStackSize = 2048;
7875
const kMincrlfDelay = 100;
7976
// \r\n, \n, or \r followed by something other than \n
80-
const lineEnding = /\r?\n|\r(?!\n)/;
77+
const lineEnding = /\r?\n|\r(?!\n)/g;
8178

8279
const kLineObjectStream = Symbol('line object stream');
8380
const kQuestionCancel = Symbol('kQuestionCancel');
@@ -590,31 +587,40 @@ class Interface extends InterfaceConstructor {
590587
this[kSawReturnAt] &&
591588
DateNow() - this[kSawReturnAt] <= this.crlfDelay
592589
) {
593-
string = RegExpPrototypeSymbolReplace(/^\n/, string, '');
590+
if (StringPrototypeCodePointAt(string) === 10) string = StringPrototypeSlice(string, 1);
594591
this[kSawReturnAt] = 0;
595592
}
596593

597594
// Run test() on the new string chunk, not on the entire line buffer.
598-
const newPartContainsEnding = RegExpPrototypeExec(lineEnding, string) !== null;
599-
600-
if (this[kLine_buffer]) {
601-
string = this[kLine_buffer] + string;
602-
this[kLine_buffer] = null;
603-
}
604-
if (newPartContainsEnding) {
595+
let newPartContainsEnding = RegExpPrototypeExec(lineEnding, string);
596+
if (newPartContainsEnding !== null) {
597+
if (this[kLine_buffer]) {
598+
string = this[kLine_buffer] + string;
599+
this[kLine_buffer] = null;
600+
newPartContainsEnding = RegExpPrototypeExec(lineEnding, string);
601+
}
605602
this[kSawReturnAt] = StringPrototypeEndsWith(string, '\r') ?
606603
DateNow() :
607604
0;
608605

609-
// Got one or more newlines; process into "line" events
610-
const lines = StringPrototypeSplit(string, lineEnding);
606+
const indexes = [0, newPartContainsEnding.index, lineEnding.lastIndex];
607+
let nextMatch;
608+
while ((nextMatch = RegExpPrototypeExec(lineEnding, string)) !== null) {
609+
ArrayPrototypePush(indexes, nextMatch.index, lineEnding.lastIndex);
610+
}
611+
const lastIndex = indexes.length - 1;
611612
// Either '' or (conceivably) the unfinished portion of the next line
612-
string = ArrayPrototypePop(lines);
613-
this[kLine_buffer] = string;
614-
for (let n = 0; n < lines.length; n++) this[kOnLine](lines[n]);
613+
this[kLine_buffer] = StringPrototypeSlice(string, indexes[lastIndex]);
614+
for (let i = 1; i < lastIndex; i += 2) {
615+
this[kOnLine](StringPrototypeSlice(string, indexes[i - 1], indexes[i]));
616+
}
615617
} else if (string) {
616618
// No newlines this time, save what we have for next time
617-
this[kLine_buffer] = string;
619+
if (this[kLine_buffer]) {
620+
this[kLine_buffer] += string;
621+
} else {
622+
this[kLine_buffer] = string;
623+
}
618624
}
619625
}
620626

@@ -1322,12 +1328,18 @@ class Interface extends InterfaceConstructor {
13221328
// falls through
13231329
default:
13241330
if (typeof s === 'string' && s) {
1325-
const lines = RegExpPrototypeSymbolSplit(/\r\n|\n|\r/, s);
1326-
for (let i = 0, len = lines.length; i < len; i++) {
1327-
if (i > 0) {
1331+
let nextMatch = RegExpPrototypeExec(lineEnding, s);
1332+
if (nextMatch !== null) {
1333+
this[kInsertString](StringPrototypeSlice(s, 0, nextMatch.index));
1334+
let { lastIndex } = lineEnding;
1335+
while ((nextMatch = RegExpPrototypeExec(lineEnding, s)) !== null) {
13281336
this[kLine]();
1337+
this[kInsertString](StringPrototypeSlice(s, lastIndex, nextMatch.index));
1338+
({ lastIndex } = lineEnding);
13291339
}
1330-
this[kInsertString](lines[i]);
1340+
if (lastIndex === s.length) this[kLine]();
1341+
} else {
1342+
this[kInsertString](s);
13311343
}
13321344
}
13331345
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.