Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion packages/bun-usockets/src/crypto/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2032,7 +2032,19 @@ static void ssl_update_handshake(struct us_socket_t *s) {
}
s->ssl_handshake_state = HANDSHAKE_PENDING;
s->ssl_write_wants_read = 1;
s->flags.last_write_failed = 1;
/* Only a blocked write justifies keeping writable interest armed. For
* WANT_READ no write failed — progress comes from the read side — and
* setting last_write_failed here kept EPOLLOUT / the EVFILT_WRITE
* one-shot re-armed on an always-writable socket: every tick re-entered
* this function with zero progress, spinning the loop at 100% CPU
* whenever writable interest existed while the handshake stalled
* (us_socket_pause arms writable, so pause() mid-handshake spun until
* resume). WANT_WRITE's blocked BIO write already set the flag inside
* us_socket_raw_write; keep this for the BIO retry paths that buffer
* without issuing a send. */
if (err == SSL_ERROR_WANT_WRITE) {
s->flags.last_write_failed = 1;
}
return;
}

Expand Down
7 changes: 7 additions & 0 deletions test/js/bun/net/socket.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@ describe.concurrent("socket", () => {
expect(await bunRun(fileURLToPath(new URL("./kqueue-filter-coalesce-fixture.ts", import.meta.url)))).toSpawn();
});

// ssl_update_handshake set last_write_failed on SSL_ERROR_WANT_READ, so a
// paused (writable-armed) socket with a stalled handshake re-fired writable
// every tick at 100% CPU until the peer's handshake bytes arrived.
it("paused TLS socket with a stalled handshake must not spin the event loop", async () => {
expect(await bunRun(fileURLToPath(new URL("./tls-handshake-pause-spin-fixture.ts", import.meta.url)))).toSpawn();
});

it("reload() should preserve active_connections (no UAF / counter underflow)", async () => {
await using proc = Bun.spawn({
cmd: [bunExe(), fileURLToPath(new URL("./socket-reload-fixture.ts", import.meta.url))],
Expand Down
42 changes: 42 additions & 0 deletions test/js/bun/net/tls-handshake-pause-spin-fixture.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading