mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
The fix and approach are from #64491 by Shivay-98; this reopens it to get it landed, since the original stalled awaiting requested changes. `Socket.prototype._unrefTimer` and `Socket.prototype._destroy` both walk the `_parent` chain with a strict `!== null` check. During connection teardown a socket's `_parent` can be left `undefined` (for example a TLS socket layered over another stream), so the loop steps onto `undefined` and reads a property off it, throwing a TypeError: Cannot read properties of undefined (reading 'Symbol(timeout)') from an uncaught I/O callback and crashing the process. Using a nullish (`!= null`) check terminates the walk on both `null` and `undefined`. [petter@hightouch.io: apply the same fix to the identical loop in `_destroy`, which the original regression test already exercised via `destroy()`; add direct unit coverage for both paths.] Fixes: https://github.com/nodejs/node/issues/64490 Refs: https://github.com/nodejs/node/pull/64491 Signed-off-by: Petter Häggholm <petter@hightouch.io> PR-URL: https://github.com/nodejs/node/pull/64644 Fixes: https://github.com/nodejs/node/issues/64490 Refs: https://github.com/nodejs/node/pull/64491 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
40 lines
1.0 KiB
JavaScript
40 lines
1.0 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
|
|
if (!common.hasCrypto)
|
|
common.skip('missing crypto');
|
|
|
|
const tls = require('tls');
|
|
const fixtures = require('../common/fixtures');
|
|
|
|
// A TLS socket whose `_parent` is left `undefined` during teardown must not
|
|
// crash when reads land on it (`onStreamRead` -> `_unrefTimer`) or when it is
|
|
// destroyed (`_destroy`). Both walk the `_parent` chain.
|
|
// Refs: https://github.com/nodejs/node/issues/64490
|
|
|
|
const options = {
|
|
key: fixtures.readKey('agent1-key.pem'),
|
|
cert: fixtures.readKey('agent1-cert.pem'),
|
|
};
|
|
|
|
const server = tls.createServer(options, common.mustCall((conn) => {
|
|
setTimeout(() => conn.write('x'), 50);
|
|
}));
|
|
|
|
server.listen(0, common.mustCall(() => {
|
|
const client = tls.connect({
|
|
port: server.address().port,
|
|
rejectUnauthorized: false,
|
|
}, common.mustCall(() => {
|
|
client._parent = undefined;
|
|
}));
|
|
|
|
client.on('data', common.mustCall(() => {
|
|
server.close();
|
|
client.destroy();
|
|
}));
|
|
|
|
client.on('error', common.mustNotCall());
|
|
}));
|