Skip to content

Commit 6962ef0

Browse files
aduh95targos
authored andcommitted
readline: improve robustness against prototype mutation
PR-URL: #45614 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 691f58e commit 6962ef0

File tree

1 file changed

+34
-22
lines changed

1 file changed

+34
-22
lines changed

lib/internal/readline/interface.js

Lines 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');
@@ -591,31 +588,40 @@ class Interface extends InterfaceConstructor {
591588
this[kSawReturnAt] &&
592589
DateNow() - this[kSawReturnAt] <= this.crlfDelay
593590
) {
594-
string = RegExpPrototypeSymbolReplace(/^\n/, string, '');
591+
if (StringPrototypeCodePointAt(string) === 10) string = StringPrototypeSlice(string, 1);
595592
this[kSawReturnAt] = 0;
596593
}
597594

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

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

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy