diff --git a/src/runtime/socket/Handlers.rs b/src/runtime/socket/Handlers.rs index 8867b87a3f6..ea00857750e 100644 --- a/src/runtime/socket/Handlers.rs +++ b/src/runtime/socket/Handlers.rs @@ -392,7 +392,11 @@ impl Handlers { #[cfg(debug_assertions)] { - debug_assert!(self.protection_count > 0); + // `Drop` runs even on the early-error returns in `from_generated` + // (before `protect()`); nothing to unprotect in that case. + if self.protection_count == 0 { + return; + } self.protection_count -= 1; } self.on_open.unprotect(); diff --git a/test/js/bun/net/socket.test.ts b/test/js/bun/net/socket.test.ts index 31836ab4f29..c2a1e338881 100644 --- a/test/js/bun/net/socket.test.ts +++ b/test/js/bun/net/socket.test.ts @@ -821,6 +821,27 @@ it("should throw on empty unix path from truthy non-string value", () => { expect(() => Bun.connect({ unix: [] as any, socket })).toThrow("SocketOptions.unix must be a string"); }); +it("should throw when socket handlers have no data or drain callback", () => { + // Handlers validation fails before protect() is called; Drop must not + // assert on an unprotected Handlers. + expect(() => Bun.listen({ hostname: "localhost", port: 0, socket: {} as any })).toThrow( + 'Expected at least "data" or "drain" callback', + ); + expect(() => Bun.connect({ hostname: "localhost", port: 0, socket: {} as any })).toThrow( + 'Expected at least "data" or "drain" callback', + ); +}); + +it("should throw when a socket handler is not a function", () => { + const socket = { open() {}, close: "not a function" } as any; + expect(() => Bun.listen({ hostname: "localhost", port: 0, socket })).toThrow( + 'Expected "onClose" callback to be a function', + ); + expect(() => Bun.connect({ hostname: "localhost", port: 0, socket })).toThrow( + 'Expected "onClose" callback to be a function', + ); +}); + it("reading .listener on a closed client socket does not use-after-free handlers", async () => { // Client-mode Handlers is heap-allocated per-connect and freed in // markInactive once the socket closes. `socket.listener` read