mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05: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>
26 lines
711 B
JavaScript
26 lines
711 B
JavaScript
'use strict';
|
|
const common = require('../common');
|
|
|
|
// Walking the `_parent` chain must stop on a nullish link, not only strict
|
|
// `null`. During connection teardown a socket's `_parent` can be left
|
|
// `undefined`, which previously caused `_unrefTimer()` and `_destroy()` to read
|
|
// a property off `undefined` and throw.
|
|
// Refs: https://github.com/nodejs/node/issues/64490
|
|
|
|
const assert = require('assert');
|
|
const net = require('net');
|
|
|
|
{
|
|
const socket = new net.Socket();
|
|
socket._parent = undefined;
|
|
socket._unrefTimer();
|
|
}
|
|
|
|
{
|
|
const socket = new net.Socket();
|
|
socket._parent = undefined;
|
|
socket.on('error', common.mustNotCall());
|
|
socket.destroy();
|
|
assert.strictEqual(socket.destroyed, true);
|
|
}
|