Skip to content

Commit

Permalink
net: fix for DialTimeout errors with large timeout
Browse files Browse the repository at this point in the history
The existing implementation converts the deadline time to an int64,
but does not handle overflow. If the calculated deadline is negative
but the user specified deadline is in the future, then we can assume
the calculation overflowed, and set the deadline to math.MaxInt64.

Fixes #14431

Change-Id: I54dbb4f02bc7ffb9cae8cf62e4e967e9c6541ec6
Reviewed-on: https://go-review.googlesource.com/19758
Reviewed-by: Ian Lance Taylor <[email protected]>
Reviewed-by: Mikio Hara <[email protected]>
  • Loading branch information
prashantv authored and cixtor committed Feb 23, 2016
1 parent d1cc7f7 commit c4cb365
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/net/fd_poll_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
}

func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
d := runtimeNano() + int64(t.Sub(time.Now()))
diff := int64(t.Sub(time.Now()))
d := runtimeNano() + diff
if d <= 0 && diff > 0 {
// If the user has a deadline in the future, but the delay calculation
// overflows, then set the deadline to the maximum possible value.
d = 1<<63 - 1
}
if t.IsZero() {
d = 0
}
Expand Down
50 changes: 50 additions & 0 deletions src/net/timeout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ var dialTimeoutTests = []struct {
{-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond},
{0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond},
{-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline
{-1 << 63, 0, time.Second, 100 * time.Millisecond},
{0, -1 << 63, time.Second, 100 * time.Millisecond},

{50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
{0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
Expand Down Expand Up @@ -99,6 +101,54 @@ func TestDialTimeout(t *testing.T) {
}
}

var dialTimeoutMaxDurationTests = []struct {
timeout time.Duration
delta time.Duration // for deadline
}{
// Large timeouts that will overflow an int64 unix nanos.
{1<<63 - 1, 0},
{0, 1<<63 - 1},
}

func TestDialTimeoutMaxDuration(t *testing.T) {
t.Parallel()

ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
}
defer ln.Close()

for i, tt := range dialTimeoutMaxDurationTests {
ch := make(chan error)
max := time.NewTimer(100 * time.Millisecond)
defer max.Stop()
go func() {
d := Dialer{Timeout: tt.timeout}
if tt.delta != 0 {
d.Deadline = time.Now().Add(tt.delta)
}
c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
if err == nil {
c.Close()
}
ch <- err
}()

select {
case <-max.C:
t.Fatalf("#%d: Dial didn't return in an expected time", i)
case err := <-ch:
if perr := parseDialError(err); perr != nil {
t.Error(perr)
}
if err != nil {
t.Errorf("#%d: %v", i, err)
}
}
}
}

var acceptTimeoutTests = []struct {
timeout time.Duration
xerrs [2]error // expected errors in transition
Expand Down

0 comments on commit c4cb365

Please sign in to comment.