Skip to content

Commit 41702ef

Browse files
addaleaxMylesBorins
authored andcommitted
tls: unconsume stream on destroy
When the TLS stream is destroyed for whatever reason, we should unset all callbacks on the underlying transport stream. PR-URL: #17478 Fixes: #17475 Reviewed-By: Fedor Indutny <[email protected]> Reviewed-By: Jan Krems <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent d879b63 commit 41702ef

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

src/tls_wrap.cc

+19-2
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,19 @@ TLSWrap::~TLSWrap() {
101101
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
102102
sni_context_.Reset();
103103
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
104+
105+
// See test/parallel/test-tls-transport-destroy-after-own-gc.js:
106+
// If this TLSWrap is garbage collected, we cannot allow callbacks to be
107+
// called on this stream.
108+
109+
if (stream_ == nullptr)
110+
return;
111+
stream_->set_destruct_cb({ nullptr, nullptr });
112+
stream_->set_after_write_cb({ nullptr, nullptr });
113+
stream_->set_alloc_cb({ nullptr, nullptr });
114+
stream_->set_read_cb({ nullptr, nullptr });
115+
stream_->set_destruct_cb({ nullptr, nullptr });
116+
stream_->Unconsume();
104117
}
105118

106119

@@ -564,12 +577,16 @@ uint32_t TLSWrap::UpdateWriteQueueSize(uint32_t write_queue_size) {
564577

565578

566579
int TLSWrap::ReadStart() {
567-
return stream_->ReadStart();
580+
if (stream_ != nullptr)
581+
return stream_->ReadStart();
582+
return 0;
568583
}
569584

570585

571586
int TLSWrap::ReadStop() {
572-
return stream_->ReadStop();
587+
if (stream_ != nullptr)
588+
return stream_->ReadStop();
589+
return 0;
573590
}
574591

575592

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Flags: --expose-gc
2+
'use strict';
3+
4+
// Regression test for https://github.com/nodejs/node/issues/17475
5+
// Unfortunately, this tests only "works" reliably when checked with valgrind or
6+
// a similar tool.
7+
8+
const common = require('../common');
9+
if (!common.hasCrypto)
10+
common.skip('missing crypto');
11+
12+
const { TLSSocket } = require('tls');
13+
const makeDuplexPair = require('../common/duplexpair');
14+
15+
let { clientSide } = makeDuplexPair();
16+
17+
let clientTLS = new TLSSocket(clientSide, { isServer: false });
18+
// eslint-disable-next-line no-unused-vars
19+
let clientTLSHandle = clientTLS._handle;
20+
21+
setImmediate(() => {
22+
clientTLS = null;
23+
global.gc();
24+
clientTLSHandle = null;
25+
global.gc();
26+
setImmediate(() => {
27+
clientSide = null;
28+
global.gc();
29+
});
30+
});

0 commit comments

Comments
 (0)