Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

process: swallow stdout/stderr error events #9470

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions lib/internal/process/stdio.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,64 @@ function setupStdio() {
function getStdout() {
if (stdout) return stdout;
stdout = createWritableStdioStream(1);

Object.defineProperty(stdout._writableState, 'ended', {
set() {},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value: true ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mutually exclusive with getters and still overwritable.

get() {
return false;
}
});
// XXX(Fishrock123): This should work I think, but it causes
// problems with some child-process related tests.
//
// Object.defineProperty(stdout, 'destroyed', {
// set() {},
// get() {
// return true;
// }
// });
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nodejs/streams this affected some other tests but I wasn't able to tell why.

=== release test-http-chunk-problem ===                                        
Path: parallel/test-http-chunk-problem
assert.js:85
  throw new assert.AssertionError({
  ^
AssertionError: '8c206a1a87599f532ce68675536f0b1546900d7a' == 'bafcbe972b6e69cd415ded38cb995f1bca983929'
    at cp.exec (/Users/Jeremiah/Documents/node/test/parallel/test-http-chunk-problem.js:55:20)
    at ChildProcess.exithandler (child_process.js:202:7)
    at emitTwo (events.js:106:13)
    at ChildProcess.emit (events.js:191:7)
    at maybeClose (internal/child_process.js:877:16)
    at Socket.<anonymous> (internal/child_process.js:334:11)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at Pipe._handle.close [as _onclose] (net.js:501:12)

&

=== release test-stdin-pipe-large ===                                          
Path: parallel/test-stdin-pipe-large
assert.js:85
  throw new assert.AssertionError({
  ^
AssertionError: 131072 === 1048576
    at Socket.child.stdout.on.common.mustCall (/Users/Jeremiah/Documents/node/test/parallel/test-stdin-pipe-large.js:22:10)
    at Socket.<anonymous> (/Users/Jeremiah/Documents/node/test/common.js:421:15)
    at emitNone (events.js:91:20)
    at Socket.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(The current patch works, but I think maybe having destroyed = true by default always would work better?) 9I don't think we can re-set it after destroy() and not hit what it is needed to skip.


stdout.destroy = stdout.destroySoon = function(er) {
stdout.destroyed = true;
er = er || new Error('process.stdout cannot be closed.');
stdout.emit('error', er);
};
if (stdout.isTTY) {
process.on('SIGWINCH', () => stdout._refreshSize());
}
stdout.on('error', () => {});
Copy link
Member

@addaleax addaleax Nov 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is a good idea. If my program writes stdout to a file and that fails, it should definitely not pass silently – if this is about making console safe, maybe something more specific to console would be a better idea?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, perhaps. I'd like to have a bit more discussion, I don't know if throwing from stdio on process is a good idea either. There are a lot of libraries that do raw writes that could be affected by e.g. EPIPE from an outside source, and that doesn't really make sense to crash on IMO.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced that we should do this in the first place. I'm with @addaleax.

Even if we land, a comment on why that handler is there is 100% needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another -1. Hiding failure != safety.

return stdout;
}

function getStderr() {
if (stderr) return stderr;
stderr = createWritableStdioStream(2);

Object.defineProperty(stderr._writableState, 'ended', {
set() {},
get() {
return false;
}
});
// XXX(Fishrock123): This should work I think, but it causes
// problems with some child-process related tests.
//
// Object.defineProperty(stderr, 'destroyed', {
// set() {},
// get() {
// return true;
// }
// });

stderr.destroy = stderr.destroySoon = function(er) {
stderr.destroyed = true;
er = er || new Error('process.stderr cannot be closed.');
stderr.emit('error', er);
};
if (stderr.isTTY) {
process.on('SIGWINCH', () => stderr._refreshSize());
}
stderr.on('error', () => {});
return stderr;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ function parent() {
});

child.on('close', function(code, signal) {
assert(code);
assert.strictEqual(code, 0, 'exit code should be zero');
assert.equal(out, 'foo');
assert(/process\.stdout cannot be closed/.test(err));
assert.strictEqual(err, '', 'stderr should be empty');
console.log('ok');
});
}
17 changes: 6 additions & 11 deletions test/pseudo-tty/test-tty-stdout-end.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
'use strict';
require('../common');
const common = require('../common');
const assert = require('assert');

const shouldThrow = function() {
process.stdout.end();
};

const validateError = function(e) {
return e instanceof Error &&
e.message === 'process.stdout cannot be closed.';
};

assert.throws(shouldThrow, validateError);
process.stdout.on('error', common.mustCall(function(e) {
assert(e instanceof Error, 'e is an Error');
assert.strictEqual(e.message, 'process.stdout cannot be closed.');
}));
process.stdout.end();