Skip to content

Commit d36b60e

Browse files
authored
readline: fix question still called after closed
resolve: #42450 PR-URL: #42464 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
1 parent 0bac547 commit d36b60e

File tree

6 files changed

+73
-1
lines changed

6 files changed

+73
-1
lines changed

doc/api/errors.md

+8
Original file line numberDiff line numberDiff line change
@@ -2802,6 +2802,14 @@ import 'package-name'; // supported
28022802

28032803
`import` with URL schemes other than `file` and `data` is unsupported.
28042804

2805+
<a id="ERR_USE_AFTER_CLOSE"></a>
2806+
2807+
### `ERR_USE_AFTER_CLOSE`
2808+
2809+
> Stability: 1 - Experimental
2810+
2811+
An attempt was made to use something that was already closed.
2812+
28052813
<a id="ERR_VALID_PERFORMANCE_ENTRY_TYPE"></a>
28062814

28072815
### `ERR_VALID_PERFORMANCE_ENTRY_TYPE`

doc/api/readline.md

+6
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ The `callback` function passed to `rl.question()` does not follow the typical
330330
pattern of accepting an `Error` object or `null` as the first argument.
331331
The `callback` is called with the provided answer as the only argument.
332332

333+
An error will be thrown if calling `rl.question()` after `rl.close()`.
334+
333335
Example usage:
334336

335337
```js
@@ -586,6 +588,8 @@ paused.
586588
If the `readlinePromises.Interface` was created with `output` set to `null` or
587589
`undefined` the `query` is not written.
588590

591+
If the question is called after `rl.close()`, it returns a rejected promise.
592+
589593
Example usage:
590594

591595
```mjs
@@ -855,6 +859,8 @@ The `callback` function passed to `rl.question()` does not follow the typical
855859
pattern of accepting an `Error` object or `null` as the first argument.
856860
The `callback` is called with the provided answer as the only argument.
857861

862+
An error will be thrown if calling `rl.question()` after `rl.close()`.
863+
858864
Example usage:
859865

860866
```js

lib/internal/errors.js

+1
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,7 @@ E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url, supported) => {
16271627
msg += `. Received protocol '${url.protocol}'`;
16281628
return msg;
16291629
}, Error);
1630+
E('ERR_USE_AFTER_CLOSE', '%s was closed', Error);
16301631

16311632
// This should probably be a `TypeError`.
16321633
E('ERR_VALID_PERFORMANCE_ENTRY_TYPE',

lib/internal/readline/interface.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ const {
3838

3939
const { codes } = require('internal/errors');
4040

41-
const { ERR_INVALID_ARG_VALUE } = codes;
41+
const {
42+
ERR_INVALID_ARG_VALUE,
43+
ERR_USE_AFTER_CLOSE,
44+
} = codes;
4245
const {
4346
validateAbortSignal,
4447
validateArray,
@@ -398,6 +401,9 @@ class Interface extends InterfaceConstructor {
398401
}
399402

400403
question(query, cb) {
404+
if (this.closed) {
405+
throw new ERR_USE_AFTER_CLOSE('readline');
406+
}
401407
if (this[kQuestionCallback]) {
402408
this.prompt();
403409
} else {

test/parallel/test-readline-interface.js

+34
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,40 @@ for (let i = 0; i < 12; i++) {
10921092
rli.close();
10931093
}
10941094

1095+
// Call question after close
1096+
{
1097+
const [rli, fi] = getInterface({ terminal });
1098+
rli.question('What\'s your name?', common.mustCall((name) => {
1099+
assert.strictEqual(name, 'Node.js');
1100+
rli.close();
1101+
assert.throws(() => {
1102+
rli.question('How are you?', common.mustNotCall());
1103+
}, {
1104+
name: 'Error',
1105+
code: 'ERR_USE_AFTER_CLOSE'
1106+
});
1107+
assert.notStrictEqual(rli.getPrompt(), 'How are you?');
1108+
}));
1109+
fi.emit('data', 'Node.js\n');
1110+
}
1111+
1112+
// Call promisified question after close
1113+
{
1114+
const [rli, fi] = getInterface({ terminal });
1115+
const question = util.promisify(rli.question).bind(rli);
1116+
question('What\'s your name?').then(common.mustCall((name) => {
1117+
assert.strictEqual(name, 'Node.js');
1118+
rli.close();
1119+
question('How are you?')
1120+
.then(common.mustNotCall(), common.expectsError({
1121+
code: 'ERR_USE_AFTER_CLOSE',
1122+
name: 'Error'
1123+
}));
1124+
assert.notStrictEqual(rli.getPrompt(), 'How are you?');
1125+
}));
1126+
fi.emit('data', 'Node.js\n');
1127+
}
1128+
10951129
// Can create a new readline Interface with a null output argument
10961130
{
10971131
const [rli, fi] = getInterface({ output: null, terminal });

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

+17
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,23 @@ for (let i = 0; i < 12; i++) {
952952
rli.close();
953953
}
954954

955+
// Call question after close
956+
{
957+
const [rli, fi] = getInterface({ terminal });
958+
rli.question('What\'s your name?').then(common.mustCall((name) => {
959+
assert.strictEqual(name, 'Node.js');
960+
rli.close();
961+
rli.question('How are you?')
962+
.then(common.mustNotCall(), common.expectsError({
963+
code: 'ERR_USE_AFTER_CLOSE',
964+
name: 'Error'
965+
}));
966+
assert.notStrictEqual(rli.getPrompt(), 'How are you?');
967+
}));
968+
fi.emit('data', 'Node.js\n');
969+
}
970+
971+
955972
// Can create a new readline Interface with a null output argument
956973
{
957974
const [rli, fi] = getInterface({ output: null, terminal });

0 commit comments

Comments
 (0)