diff options
Diffstat (limited to 'src/pkg')
| -rw-r--r-- | src/pkg/bufio/bufio.go | 17 | ||||
| -rw-r--r-- | src/pkg/bufio/bufio_test.go | 22 | ||||
| -rw-r--r-- | src/pkg/runtime/proc.c | 2 | ||||
| -rw-r--r-- | src/pkg/runtime/time.goc | 5 | ||||
| -rw-r--r-- | src/pkg/syscall/rlimit_linux_test.go | 41 | ||||
| -rw-r--r-- | src/pkg/syscall/syscall_linux_386.go | 4 | ||||
| -rw-r--r-- | src/pkg/syscall/syscall_linux_arm.go | 4 | ||||
| -rw-r--r-- | src/pkg/time/sleep_test.go | 20 |
8 files changed, 105 insertions, 10 deletions
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go index df3501f2c..10e12d42b 100644 --- a/src/pkg/bufio/bufio.go +++ b/src/pkg/bufio/bufio.go @@ -585,23 +585,28 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) { } var m int for { + if b.Available() == 0 { + if err1 := b.Flush(); err1 != nil { + return n, err1 + } + } m, err = r.Read(b.buf[b.n:]) if m == 0 { break } b.n += m n += int64(m) - if b.Available() == 0 { - if err1 := b.Flush(); err1 != nil { - return n, err1 - } - } if err != nil { break } } if err == io.EOF { - err = nil + // If we filled the buffer exactly, flush pre-emptively. + if b.Available() == 0 { + err = b.Flush() + } else { + err = nil + } } return n, err } diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go index 79ed0f178..9fcbfda68 100644 --- a/src/pkg/bufio/bufio_test.go +++ b/src/pkg/bufio/bufio_test.go @@ -847,6 +847,10 @@ func TestWriterReadFrom(t *testing.T) { t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input)) continue } + if err := w.Flush(); err != nil { + t.Errorf("Flush returned %v", err) + continue + } if got, want := b.String(), string(input); got != want { t.Errorf("ws[%d], rs[%d]:\ngot %q\nwant %q\n", wi, ri, got, want) } @@ -1003,6 +1007,24 @@ func TestReaderClearError(t *testing.T) { } } +// Test for golang.org/issue/5947 +func TestWriterReadFromWhileFull(t *testing.T) { + buf := new(bytes.Buffer) + w := NewWriterSize(buf, 10) + + // Fill buffer exactly. + n, err := w.Write([]byte("0123456789")) + if n != 10 || err != nil { + t.Fatalf("Write returned (%v, %v), want (10, nil)", n, err) + } + + // Use ReadFrom to read in some data. + n2, err := w.ReadFrom(strings.NewReader("abcdef")) + if n2 != 6 || err != nil { + t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err) + } +} + // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have. type onlyReader struct { r io.Reader diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 31876b62a..5734509e0 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -1371,6 +1371,8 @@ runtime·exitsyscall(void) runtime·unlock(&runtime·sched); if(p) { acquirep(p); + m->p->tick++; + g->status = Grunning; g->gcstack = (uintptr)nil; g->gcsp = (uintptr)nil; return; diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc index 6de989f51..be0c1f83d 100644 --- a/src/pkg/runtime/time.goc +++ b/src/pkg/runtime/time.goc @@ -131,6 +131,11 @@ runtime·deltimer(Timer *t) { int32 i; + // Dereference t so that any panic happens before the lock is held. + // Discard result, because t might be moving in the heap. + i = t->i; + USED(i); + runtime·lock(&timers); // t may not be registered anymore and may have diff --git a/src/pkg/syscall/rlimit_linux_test.go b/src/pkg/syscall/rlimit_linux_test.go new file mode 100644 index 000000000..4ec720e93 --- /dev/null +++ b/src/pkg/syscall/rlimit_linux_test.go @@ -0,0 +1,41 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall_test + +import ( + "syscall" + "testing" +) + +func TestRlimit(t *testing.T) { + var rlimit, zero syscall.Rlimit + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + t.Fatalf("Getrlimit: save failed: %v", err) + } + if zero == rlimit { + t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) + } + set := rlimit + set.Cur = set.Max - 1 + err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &set) + if err != nil { + t.Fatalf("Setrlimit: set failed: %#v %v", set, err) + } + var get syscall.Rlimit + err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &get) + if err != nil { + t.Fatalf("Getrlimit: get failed: %v", err) + } + set = rlimit + set.Cur = set.Max - 1 + if set != get { + t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) + } + err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit) + if err != nil { + t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) + } +} diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go index a0ded43dc..a61695676 100644 --- a/src/pkg/syscall/syscall_linux_386.go +++ b/src/pkg/syscall/syscall_linux_386.go @@ -78,7 +78,7 @@ const rlimInf32 = ^uint32(0) const rlimInf64 = ^uint64(0) func Getrlimit(resource int, rlim *Rlimit) (err error) { - err = prlimit(0, resource, rlim, nil) + err = prlimit(0, resource, nil, rlim) if err != ENOSYS { return err } @@ -106,7 +106,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { //sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT func Setrlimit(resource int, rlim *Rlimit) (err error) { - err = prlimit(0, resource, nil, rlim) + err = prlimit(0, resource, rlim, nil) if err != ENOSYS { return err } diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go index 7839d5288..4aadf9e4c 100644 --- a/src/pkg/syscall/syscall_linux_arm.go +++ b/src/pkg/syscall/syscall_linux_arm.go @@ -119,7 +119,7 @@ const rlimInf32 = ^uint32(0) const rlimInf64 = ^uint64(0) func Getrlimit(resource int, rlim *Rlimit) (err error) { - err = prlimit(0, resource, rlim, nil) + err = prlimit(0, resource, nil, rlim) if err != ENOSYS { return err } @@ -147,7 +147,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { //sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT func Setrlimit(resource int, rlim *Rlimit) (err error) { - err = prlimit(0, resource, nil, rlim) + err = prlimit(0, resource, rlim, nil) if err != ENOSYS { return err } diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go index 1322f0611..603adc9b8 100644 --- a/src/pkg/time/sleep_test.go +++ b/src/pkg/time/sleep_test.go @@ -314,3 +314,23 @@ func TestOverflowSleep(t *testing.T) { t.Fatalf("negative timeout didn't fire") } } + +// Test that a panic while deleting a timer does not leave +// the timers mutex held, deadlocking a ticker.Stop in a defer. +func TestIssue5745(t *testing.T) { + ticker := NewTicker(Hour) + defer func() { + // would deadlock here before the fix due to + // lock taken before the segfault. + ticker.Stop() + + if r := recover(); r == nil { + t.Error("Expected panic, but none happened.") + } + }() + + // cause a panic due to a segfault + var timer *Timer + timer.Stop() + t.Error("Should be unreachable.") +} |
