Skip to content

Commit 91eec00

Browse files
committed
tty: make _read throw ERR_TTY_WRITABLE_NOT_READABLE
This change avoid an 'read ENOTCONN' error introduced by libuv 1.20.0 when trying to read from a TTY WriteStream. Instead, we are throwing a more actionable ERR_TTY_WRITABLE_NOT_READABLE. Fixes: #21203 PR-URL: #21654 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Shingo Inoue <leko.noor@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 6acb550 commit 91eec00

File tree

5 files changed

+38
-1
lines changed

5 files changed

+38
-1
lines changed

doc/api/errors.md

+6
Original file line numberDiff line numberDiff line change
@@ -1694,6 +1694,12 @@ A `Transform` stream finished with data still in the write buffer.
16941694

16951695
The initialization of a TTY failed due to a system error.
16961696

1697+
<a id="ERR_TTY_WRITABLE_NOT_READABLE"></a>
1698+
### ERR_TTY_WRITABLE_NOT_READABLE
1699+
1700+
This `Error` is thrown when a read is attempted on a TTY `WriteStream`,
1701+
such as `process.stdout.on('data')`.
1702+
16971703
<a id="ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET"></a>
16981704
### ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET
16991705

lib/internal/errors.js

+3
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,9 @@ E('ERR_TRANSFORM_ALREADY_TRANSFORMING',
828828
E('ERR_TRANSFORM_WITH_LENGTH_0',
829829
'Calling transform done when writableState.length != 0', Error);
830830
E('ERR_TTY_INIT_FAILED', 'TTY initialization failed', SystemError);
831+
E('ERR_TTY_WRITABLE_NOT_READABLE',
832+
'The Writable side of a TTY is not Readable',
833+
Error);
831834
E('ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET',
832835
'`process.setupUncaughtExceptionCapture()` was called while a capture ' +
833836
'callback was already active',

lib/tty.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ const { inherits, _extend } = require('util');
2525
const net = require('net');
2626
const { TTY, isTTY } = process.binding('tty_wrap');
2727
const errors = require('internal/errors');
28-
const { ERR_INVALID_FD, ERR_TTY_INIT_FAILED } = errors.codes;
28+
const {
29+
ERR_INVALID_FD,
30+
ERR_TTY_INIT_FAILED,
31+
ERR_TTY_WRITABLE_NOT_READABLE
32+
} = errors.codes;
2933
const { getColorDepth } = require('internal/tty');
3034

3135
// Lazy loaded for startup performance.
@@ -122,6 +126,13 @@ WriteStream.prototype._refreshSize = function() {
122126
}
123127
};
124128

129+
// A WriteStream is not readable from, so _read become a no-op.
130+
// this method could still be called because net.Socket()
131+
// is a duplex
132+
WriteStream.prototype._read = function() {
133+
this.destroy(new ERR_TTY_WRITABLE_NOT_READABLE());
134+
};
135+
125136
// Backwards-compat
126137
WriteStream.prototype.cursorTo = function(x, y) {
127138
if (readline === undefined) readline = require('readline');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const { WriteStream } = require('tty');
5+
const fd = common.getTTYfd();
6+
7+
// Calling resume on a tty.WriteStream should be a no-op
8+
// Ref: https://github.com/nodejs/node/issues/21203
9+
10+
const stream = new WriteStream(fd);
11+
stream.resume();
12+
13+
stream.on('error', common.expectsError({
14+
code: 'ERR_TTY_WRITABLE_NOT_READABLE',
15+
type: Error,
16+
message: 'The Writable side of a TTY is not Readable'
17+
}));

test/pseudo-tty/test-tty-write-stream-resume-crash.out

Whitespace-only changes.

0 commit comments

Comments
 (0)