Skip to content

Commit 7e8a00a

Browse files
chapkodanielleadams
authored andcommitted
readline: fix question stack overflow
This commit fixes readline interface's question callback wrapping when it is being called with `signal` option. Previous version completely overwrites passed callback and throws "Maximum call stack size exceeded" error. PR-URL: #43320 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 112518f commit 7e8a00a

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

lib/readline.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,10 @@ Interface.prototype.question = function(query, options, cb) {
148148
const cleanup = () => {
149149
options.signal.removeEventListener(onAbort);
150150
};
151+
const originalCb = cb;
151152
cb = typeof cb === 'function' ? (answer) => {
152153
cleanup();
153-
return cb(answer);
154+
return originalCb(answer);
154155
} : cleanup;
155156
}
156157

test/parallel/test-readline-interface.js

+24
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,17 @@ for (let i = 0; i < 12; i++) {
10061006
rli.close();
10071007
}
10081008

1009+
// Calling the question callback with abort signal
1010+
{
1011+
const [rli] = getInterface({ terminal });
1012+
const { signal } = new AbortController();
1013+
rli.question('foo?', { signal }, common.mustCall((answer) => {
1014+
assert.strictEqual(answer, 'bar');
1015+
}));
1016+
rli.write('bar\n');
1017+
rli.close();
1018+
}
1019+
10091020
// Calling the question multiple times
10101021
{
10111022
const [rli] = getInterface({ terminal });
@@ -1030,6 +1041,19 @@ for (let i = 0; i < 12; i++) {
10301041
rli.close();
10311042
}
10321043

1044+
// Calling the promisified question with abort signal
1045+
{
1046+
const [rli] = getInterface({ terminal });
1047+
const question = util.promisify(rli.question).bind(rli);
1048+
const { signal } = new AbortController();
1049+
question('foo?', { signal })
1050+
.then(common.mustCall((answer) => {
1051+
assert.strictEqual(answer, 'bar');
1052+
}));
1053+
rli.write('bar\n');
1054+
rli.close();
1055+
}
1056+
10331057
// Aborting a question
10341058
{
10351059
const ac = new AbortController();

test/parallel/test-readline-promises-interface.js

+11
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,17 @@ for (let i = 0; i < 12; i++) {
909909
rli.close();
910910
}
911911

912+
// Calling the question callback with abort signal
913+
{
914+
const [rli] = getInterface({ terminal });
915+
const { signal } = new AbortController();
916+
rli.question('foo?', { signal }).then(common.mustCall((answer) => {
917+
assert.strictEqual(answer, 'bar');
918+
}));
919+
rli.write('bar\n');
920+
rli.close();
921+
}
922+
912923
// Aborting a question
913924
{
914925
const ac = new AbortController();

0 commit comments

Comments
 (0)