Skip to content

Commit 9403eb7

Browse files
efekrskladuh95
authored andcommitted
quic: fix no onstream handler crash quic
Signed-off-by: Efe Karasakal <hi@efe.dev> PR-URL: #64158 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
1 parent 4f232ce commit 9403eb7

5 files changed

Lines changed: 62 additions & 2 deletions

File tree

src/quic/application.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,12 @@ class DefaultApplication final : public Session::Application {
761761
// during the onstream callback (via MakeCallback re-entrancy).
762762
return false;
763763
}
764+
765+
// The stream was created, but was immediately destroyed because there's
766+
// no onstream handler.
767+
if (stream->is_destroyed()) [[unlikely]] {
768+
return true;
769+
}
764770
} else {
765771
stream = BaseObjectPtr<Stream>(Stream::From(stream_user_data));
766772
if (!stream) {

src/quic/session.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -860,11 +860,11 @@ struct Session::Impl final : public MemoryRetainer {
860860
}
861861
}
862862

863-
endpoint->RemoveSession(config_.scid, remote_address_);
864-
865863
auto& binding = BindingData::Get(env());
866864
if (stats_slot_) GetSessionStatsArena(binding).ReleaseSlot(stats_slot_);
867865
if (state_slot_) GetSessionStateArena(binding).ReleaseSlot(state_slot_);
866+
867+
endpoint->RemoveSession(config_.scid, remote_address_);
868868
}
869869

870870
void MemoryInfo(MemoryTracker* tracker) const override {

src/quic/streams.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,10 @@ bool Stream::is_pending() const {
13251325
return state()->pending;
13261326
}
13271327

1328+
bool Stream::is_destroyed() const {
1329+
return stats()->destroyed_at != 0;
1330+
}
1331+
13281332
stream_id Stream::id() const {
13291333
return state()->id;
13301334
}

src/quic/streams.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ class Stream final : public AsyncWrap,
267267
// to be created.
268268
bool is_pending() const;
269269

270+
// True if the stream is already destroyed.
271+
bool is_destroyed() const;
272+
270273
// True if we've completely sent all outbound data for this stream.
271274
// Importantly, this does not necessarily mean that we are completely
272275
// done with the outbound data. We may still be waiting on outbound
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Flags: --experimental-quic --no-warnings
2+
// Test: client-initiated unidirectional stream with no onstream
3+
// The client creates a uni stream with no onstream.
4+
// Verify that this causes no crash.
5+
6+
import { hasQuic, skip, mustCall } from '../common/index.mjs';
7+
import * as fixtures from '../common/fixtures.mjs';
8+
9+
const { readKey } = fixtures;
10+
11+
if (!hasQuic) {
12+
skip('QUIC is not enabled');
13+
}
14+
15+
const { createPrivateKey } = await import('node:crypto');
16+
const { listen, connect } = await import('../common/quic.mjs');
17+
18+
const serverKey = createPrivateKey(readKey('agent1-key.pem'));
19+
const serverCert = readKey('agent1-cert.pem');
20+
21+
const done = Promise.withResolvers();
22+
23+
const serverEndpoint = await listen(mustCall(async (session) => {
24+
await session.opened;
25+
done.resolve();
26+
}), {
27+
sni: { '*': { keys: [serverKey], certs: [serverCert] } },
28+
alpn: ['repro'],
29+
});
30+
31+
const clientSession = await connect(serverEndpoint.address, {
32+
servername: 'localhost',
33+
alpn: 'repro',
34+
ca: serverCert,
35+
});
36+
37+
await clientSession.opened;
38+
39+
await clientSession.createUnidirectionalStream({
40+
body: 'something something darkside',
41+
});
42+
43+
await done.promise;
44+
45+
await clientSession.close();
46+
47+
await serverEndpoint.close();

0 commit comments

Comments
 (0)