GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — quic: fix no onstream handler crash quic · nodejs/node@a682b53

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • src/quic
    • application.cc
    • session.cc
    • streams.cc
    • streams.h
  • test/parallel
    • test-quic-stream-uni-no-onstream.mjs
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/quic/application.cc‎

Copy file name to clipboardExpand all lines: src/quic/application.cc
+6Lines 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) {
Collapse file

‎src/quic/session.cc‎

Copy file name to clipboardExpand all lines: src/quic/session.cc
+2-2Lines 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 {
Collapse file

‎src/quic/streams.cc‎

Copy file name to clipboardExpand all lines: src/quic/streams.cc
+4Lines 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
}
Collapse file

‎src/quic/streams.h‎

Copy file name to clipboardExpand all lines: src/quic/streams.h
+3Lines 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
Collapse file

‎test/parallel/test-quic-stream-uni-no-onstream.mjs‎

Copy file name to clipboard
+47Lines 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 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.