Skip to content

Commit 7719016

Browse files
g7rianlancetaylor
authored andcommitted
net: fix improper Context.Deadline usage in DialContext
The existing implementation is erroneously assume that having no deadline in context.Context means that time returned from Deadline method will have IsZero() == true. But technically speaking this is an invalid assumption. The context.Context interface specification doesn't specify what time should be returned from Deadline method when there is no deadline set. It only specifies that second result of Deadline should be false. Fixes #35594 Change-Id: Ife00aad77ab3585e469f15017550ac6c0431b140 Reviewed-on: https://go-review.googlesource.com/c/go/+/207297 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 4de3c7d commit 7719016

File tree

3 files changed

+44
-14
lines changed

3 files changed

+44
-14
lines changed

src/net/dial.go

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -529,20 +529,21 @@ func (sd *sysDialer) dialSerial(ctx context.Context, ras addrList) (Conn, error)
529529
default:
530530
}
531531

532-
deadline, _ := ctx.Deadline()
533-
partialDeadline, err := partialDeadline(time.Now(), deadline, len(ras)-i)
534-
if err != nil {
535-
// Ran out of time.
536-
if firstErr == nil {
537-
firstErr = &OpError{Op: "dial", Net: sd.network, Source: sd.LocalAddr, Addr: ra, Err: err}
538-
}
539-
break
540-
}
541532
dialCtx := ctx
542-
if partialDeadline.Before(deadline) {
543-
var cancel context.CancelFunc
544-
dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
545-
defer cancel()
533+
if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
534+
partialDeadline, err := partialDeadline(time.Now(), deadline, len(ras)-i)
535+
if err != nil {
536+
// Ran out of time.
537+
if firstErr == nil {
538+
firstErr = &OpError{Op: "dial", Net: sd.network, Source: sd.LocalAddr, Addr: ra, Err: err}
539+
}
540+
break
541+
}
542+
if partialDeadline.Before(deadline) {
543+
var cancel context.CancelFunc
544+
dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
545+
defer cancel()
546+
}
546547
}
547548

548549
c, err := sd.dialSingle(dialCtx, ra)

src/net/dial_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,3 +980,32 @@ func mustHaveExternalNetwork(t *testing.T) {
980980
testenv.MustHaveExternalNetwork(t)
981981
}
982982
}
983+
984+
type contextWithNonZeroDeadline struct {
985+
context.Context
986+
}
987+
988+
func (contextWithNonZeroDeadline) Deadline() (time.Time, bool) {
989+
// Return non-zero time.Time value with false indicating that no deadline is set.
990+
return time.Unix(0, 0), false
991+
}
992+
993+
func TestDialWithNonZeroDeadline(t *testing.T) {
994+
ln, err := newLocalListener("tcp")
995+
if err != nil {
996+
t.Fatal(err)
997+
}
998+
defer ln.Close()
999+
_, port, err := SplitHostPort(ln.Addr().String())
1000+
if err != nil {
1001+
t.Fatal(err)
1002+
}
1003+
1004+
ctx := contextWithNonZeroDeadline{Context: context.Background()}
1005+
var dialer Dialer
1006+
c, err := dialer.DialContext(ctx, "tcp", JoinHostPort("", port))
1007+
if err != nil {
1008+
t.Fatal(err)
1009+
}
1010+
c.Close()
1011+
}

src/net/fd_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa sysc
9696
if err := fd.pfd.Init(fd.net, true); err != nil {
9797
return nil, err
9898
}
99-
if deadline, _ := ctx.Deadline(); !deadline.IsZero() {
99+
if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
100100
fd.pfd.SetWriteDeadline(deadline)
101101
defer fd.pfd.SetWriteDeadline(noDeadline)
102102
}

0 commit comments

Comments
 (0)