Skip to content

Commit 0db2eed

Browse files
committed
XXX write before destroy can fail after-the-fact
This is a bug, it isn't supposed to happen, but how to prevent it? When TLS finishes the DoWrite the underlying stream is closed, so the stream_resource()->Write() in EncOut() fails with write-after-destroy. See test/parallel/test-tls-destroy-stream.js, and its inline comments.
1 parent f978966 commit 0db2eed

File tree

4 files changed

+30
-8
lines changed

4 files changed

+30
-8
lines changed

lib/net.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,7 @@ Socket.prototype._destroy = function(exception, cb) {
581581
this[kBytesRead] = this._handle.bytesRead;
582582
this[kBytesWritten] = this._handle.bytesWritten;
583583

584+
// process._rawDebug('handle.close', this._handle.close+'');
584585
this._handle.close(() => {
585586
debug('emit close');
586587
this.emit('close', isException);

src/js_stream.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ void JSStream::New(const FunctionCallbackInfo<Value>& args) {
153153

154154
template <class Wrap>
155155
void JSStream::Finish(const FunctionCallbackInfo<Value>& args) {
156+
// finishShutdown?
156157
CHECK(args[0]->IsObject());
157158
Wrap* w = static_cast<Wrap*>(StreamReq::FromObject(args[0].As<Object>()));
158159

src/node_crypto.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,9 @@ void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) {
27322732

27332733
template <class Base>
27342734
void SSLWrap<Base>::DestroySSL() {
2735+
fprintf(stderr, "%s SSLWrap::DestroySSL() ssl? %d\n",
2736+
is_server() ? "server" : "client", !!ssl_);
2737+
27352738
if (!ssl_)
27362739
return;
27372740

test/parallel/test-tls-destroy-stream.js

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const net = require('net');
99
const assert = require('assert');
1010
const tls = require('tls');
1111

12-
tls.DEFAULT_MAX_VERSION = 'TLSv1.3';
12+
tls.DEFAULT_MAX_VERSION = 'TLSv1.3'; // XXX Switch to 1.2 to see old behaviour
1313

1414
// This test ensures that an instance of StreamWrap should emit "end" and
1515
// "close" when the socket on the other side call `destroy()` instead of
@@ -18,25 +18,42 @@ tls.DEFAULT_MAX_VERSION = 'TLSv1.3';
1818
const CONTENT = 'Hello World';
1919
const tlsServer = tls.createServer(
2020
{
21+
maxVersion: 'TLSv1.3', // passes with 1.2
2122
key: fixtures.readSync('test_key.pem'),
2223
cert: fixtures.readSync('test_cert.pem'),
2324
ca: [fixtures.readSync('test_ca.pem')],
2425
},
2526
(socket) => {
26-
console.log('tls server connection');
27-
//socket.on('error', common.mustNotCall(console.log));
28-
socket.on('close', common.mustCall());
29-
socket.write(CONTENT);
27+
process._rawDebug('server on secureConnection', socket.getProtocol());
28+
socket.on('error', (err) => {
29+
process._rawDebug('server on error:', err);
30+
// process.reallyExit(7);
31+
//XXX assert.ifError(err);
32+
});
33+
socket.on('close', common.mustCall((hadError) => {
34+
process._rawDebug('server on close: hadError?', hadError);
35+
// XXX? assert.ok(hadError);
36+
}));
37+
// XXX destroy() tears down socket before CONTENT gets flushed. probably
38+
// because of key update messages... confirm this with tracing. Is it
39+
// a bug in the test?
40+
process._rawDebug('server socket.write()');
41+
socket.write(CONTENT, (err) => {
42+
process._rawDebug('server write cb, err:', err);
43+
// process.reallyExit(9);
44+
});
45+
process._rawDebug('server socket.destroy()');
3046
socket.destroy();
47+
//process.reallyExit(3);
3148
},
3249
);
3350

3451
const server = net.createServer((conn) => {
35-
console.log('net server connection');
52+
process._rawDebug('net server connection');
3653
conn.on('error', common.mustNotCall());
3754
// Assume that we want to use data to determine what to do with connections.
3855
conn.once('data', common.mustCall((chunk) => {
39-
console.log('net conn data');
56+
process._rawDebug('net conn data');
4057
const { clientSide, serverSide } = makeDuplexPair();
4158
serverSide.on('close', common.mustCall(() => {
4259
conn.destroy();
@@ -52,7 +69,7 @@ const server = net.createServer((conn) => {
5269
}));
5370

5471
process.nextTick(() => {
55-
console.log('net conn unshift data');
72+
process._rawDebug('net conn unshift data');
5673
conn.unshift(chunk);
5774
});
5875

0 commit comments

Comments
 (0)