Skip to content

Commit da73141

Browse files
committed
test: add regression test for quic UpdateDataStats null-deref
Exercises the crash path in Session::SendDataStats() where on_exit fires UpdateDataStats() after Destroy() has already reset impl_ to nullptr. Refs: #62126
1 parent cabca4b commit da73141

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Flags: --experimental-quic --no-warnings
2+
// Regression test for https://github.com/nodejs/node/pull/62126
3+
// UpdateDataStats() must not crash when called after the session's impl_ has
4+
// been reset to null (i.e. after the session is destroyed).
5+
//
6+
// The crash path is in Session::SendDatagram():
7+
// auto on_exit = OnScopeLeave([&] { ...; UpdateDataStats(); });
8+
// If the send encounters an error it calls Close(SILENT) → Destroy() →
9+
// impl_.reset(). The on_exit lambda then fires with impl_ == nullptr.
10+
11+
import { hasQuic, skip, mustCall } from '../common/index.mjs';
12+
import * as fixtures from '../common/fixtures.mjs';
13+
14+
if (!hasQuic) {
15+
skip('QUIC is not enabled');
16+
}
17+
18+
const { listen, connect } = await import('node:quic');
19+
const { createPrivateKey } = await import('node:crypto');
20+
21+
const keys = createPrivateKey(fixtures.readKey('agent1-key.pem'));
22+
const certs = fixtures.readKey('agent1-cert.pem');
23+
24+
// Datagrams must be enabled on both sides for sendDatagram() to work.
25+
const kDatagramOptions = {
26+
transportParams: {
27+
maxDatagramFrameSize: 1200n,
28+
},
29+
};
30+
31+
const serverEndpoint = await listen(
32+
mustCall((serverSession) => {
33+
serverSession.opened.then(mustCall(async () => {
34+
// Send a datagram then immediately close. This exercises the
35+
// UpdateDataStats() call that fires via on_exit after SendDatagram —
36+
// the close can race with or precede the stats update, leaving
37+
// impl_ == nullptr. Before the fix this would crash.
38+
serverSession.sendDatagram(Buffer.from('hello')).catch(() => {});
39+
serverSession.close();
40+
}));
41+
}),
42+
{ keys, certs, ...kDatagramOptions },
43+
);
44+
45+
const clientSession = await connect(serverEndpoint.address, kDatagramOptions);
46+
await clientSession.opened;
47+
48+
// Mirror the race on the client side.
49+
clientSession.sendDatagram(Buffer.from('world')).catch(() => {});
50+
clientSession.close();
51+
52+
await clientSession.closed;
53+
serverEndpoint.close();
54+
await serverEndpoint.closed;

0 commit comments

Comments
 (0)