Skip to content

Commit a55f5d5

Browse files
dario-piotrowiczRafaelGSS
authored andcommitted
readline: add stricter validation for functions called after closed
PR-URL: #57680 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Edy Silva <edigleyssonsilva@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 87fd838 commit a55f5d5

7 files changed

Lines changed: 73 additions & 14 deletions

‎lib/internal/readline/interface.js‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,9 @@ class Interface extends InterfaceConstructor {
599599
* @returns {void | Interface}
600600
*/
601601
pause(){
602+
if(this.closed){
603+
thrownewERR_USE_AFTER_CLOSE('readline');
604+
}
602605
if(this.paused)return;
603606
this.input.pause();
604607
this.paused=true;
@@ -611,6 +614,9 @@ class Interface extends InterfaceConstructor {
611614
* @returns {void | Interface}
612615
*/
613616
resume(){
617+
if(this.closed){
618+
thrownewERR_USE_AFTER_CLOSE('readline');
619+
}
614620
if(!this.paused)return;
615621
this.input.resume();
616622
this.paused=false;
@@ -631,6 +637,9 @@ class Interface extends InterfaceConstructor {
631637
* @returns {void}
632638
*/
633639
write(d,key){
640+
if(this.closed){
641+
thrownewERR_USE_AFTER_CLOSE('readline');
642+
}
634643
if(this.paused)this.resume();
635644
if(this.terminal){
636645
this[kTtyWrite](d,key);

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,47 @@ for (let i = 0; i < 12; i++) {
12021202
fi.emit('data','Node.js\n');
12031203
}
12041204

1205+
// Call write after close
1206+
{
1207+
const[rli,fi]=getInterface({ terminal });
1208+
rli.question('What\'s your name?',common.mustCall((name)=>{
1209+
assert.strictEqual(name,'Node.js');
1210+
rli.close();
1211+
assert.throws(()=>{
1212+
rli.write('I said Node.js');
1213+
},{
1214+
name: 'Error',
1215+
code: 'ERR_USE_AFTER_CLOSE'
1216+
});
1217+
}));
1218+
fi.emit('data','Node.js\n');
1219+
}
1220+
1221+
// Call pause/resume after close
1222+
{
1223+
const[rli,fi]=getInterface({ terminal });
1224+
rli.question('What\'s your name?',common.mustCall((name)=>{
1225+
assert.strictEqual(name,'Node.js');
1226+
rli.close();
1227+
// No 'resume' nor 'pause' event should be emitted after close
1228+
rli.on('resume',common.mustNotCall());
1229+
rli.on('pause',common.mustNotCall());
1230+
assert.throws(()=>{
1231+
rli.pause();
1232+
},{
1233+
name: 'Error',
1234+
code: 'ERR_USE_AFTER_CLOSE'
1235+
});
1236+
assert.throws(()=>{
1237+
rli.resume();
1238+
},{
1239+
name: 'Error',
1240+
code: 'ERR_USE_AFTER_CLOSE'
1241+
});
1242+
}));
1243+
fi.emit('data','Node.js\n');
1244+
}
1245+
12051246
// Can create a new readline Interface with a null output argument
12061247
{
12071248
const[rli,fi]=getInterface({output: null, terminal });

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ function assertCursorRowsAndCols(rli, rows, cols) {
204204
fi.emit('data',character);
205205
}
206206
fi.emit('data','\n');
207-
rli.close();
207+
fi.end();
208208
}
209209

210210
// \t when there is no completer function should behave like an ordinary

‎test/parallel/test-readline-promises-tab-complete.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ if (process.env.TERM === 'dumb') {
8080
output='';
8181
});
8282
}
83-
rli.close();
83+
fi.end();
8484
});
8585
});
8686
});
@@ -114,5 +114,5 @@ if (process.env.TERM === 'dumb') {
114114
assert.match(output,/^Tabcompletionerror:Error:message/);
115115
output='';
116116
});
117-
rli.close();
117+
fi.end();
118118
}

‎test/parallel/test-repl-import-referrer.js‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,24 @@ const args = ['--interactive'];
88
constopts={cwd: fixtures.path('es-modules')};
99
constchild=cp.spawn(process.execPath,args,opts);
1010

11-
letoutput='';
11+
constoutputs=[];
1212
child.stdout.setEncoding('utf8');
1313
child.stdout.on('data',(data)=>{
14-
output+=data;
14+
outputs.push(data);
15+
if(outputs.length===3){
16+
// All the expected outputs have been received
17+
// so we can close the child process's stdin
18+
child.stdin.end();
19+
}
1520
});
1621

1722
child.on('exit',common.mustCall(()=>{
18-
constresults=output.replace(/^>/mg,'').split('\n').slice(2);
19-
assert.deepStrictEqual(
23+
constresults=outputs[2].split('\n')[0];
24+
assert.strictEqual(
2025
results,
21-
['[Module: null prototype] { message: \'A message\' }','']
26+
'[Module: null prototype] { message: \'A message\' }'
2227
);
2328
}));
2429

2530
child.stdin.write('await import(\'./message.mjs\');\n');
2631
child.stdin.write('.exit');
27-
child.stdin.end();
Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
'use strict';
22
constcommon=require('../common');
3-
3+
constArrayStream=require('../common/arraystream');
44
constrepl=require('repl');
5-
constr=repl.start({terminal: false});
6-
r.setupHistory('/nonexistent/file',common.mustSucceed());
7-
process.stdin.unref?.();
5+
6+
conststream=newArrayStream();
7+
8+
constreplServer=repl.start({terminal: false,input: stream,output: stream});
9+
10+
replServer.setupHistory('/nonexistent/file',common.mustSucceed(()=>{
11+
replServer.close();
12+
}));

‎test/parallel/test-repl-uncaught-exception-async.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ r.write(
3434
' throw new RangeError("abc");\n'+
3535
'}, 1);console.log()\n'
3636
);
37-
r.close();
3837

3938
setTimeout(()=>{
39+
r.close();
4040
constlen=process.listenerCount('uncaughtException');
4141
process.removeAllListeners('uncaughtException');
4242
assert.strictEqual(len,0);

0 commit comments

Comments
 (0)