From 55065073137a3aa2ec913c7480036a6bc70efbf2 Mon Sep 17 00:00:00 2001 From: Viktor Liu Date: Tue, 21 Apr 2026 15:50:24 +0200 Subject: [PATCH] netrelay: wait for endpoint close before Relay returns The closer goroutine ran asynchronously on ctx cancellation, so the "fully closed when Relay returns" guarantee was racy: callers could see the function return before a and b were actually Close()d. Wait on a done channel in the defer so the guarantee holds. --- util/netrelay/relay.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util/netrelay/relay.go b/util/netrelay/relay.go index 137ac3875..de44d5bcd 100644 --- a/util/netrelay/relay.go +++ b/util/netrelay/relay.go @@ -74,12 +74,17 @@ type Options struct { // returned because a relay always terminates on some kind of EOF/cancel. func Relay(ctx context.Context, a, b io.ReadWriteCloser, opts Options) (aToB, bToA int64) { ctx, cancel := context.WithCancel(ctx) - defer cancel() + closeDone := make(chan struct{}) + defer func() { + cancel() + <-closeDone + }() go func() { <-ctx.Done() _ = a.Close() _ = b.Close() + close(closeDone) }() // Both sides must support CloseWrite to propagate half-close. If either