Closed
Description
What version of Go are you using (go version
)?
$ go version go version go1.12 linux/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GOARCH="amd64" GOBIN="" GOCACHE="/home/januszm/.cache/go-build" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/januszm/.go" GOPROXY="" GORACE="" GOROOT="/usr/local/go" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build489382708=/tmp/go-build -gno-record-gcc-switches"
What did you do?
Run following script with: go run -race concept.go
package main
import (
"crypto/rand"
"fmt"
"io"
"io/ioutil"
"net/http"
"sync"
"time"
)
const (
addr1 = "localhost:8060"
addr2 = "localhost:8061"
)
type customReader struct {
iter int
size int
}
func (r *customReader) Read(b []byte) (int, error) {
maxRead := r.size - r.iter
if maxRead == 0 {
return 0, io.EOF
}
if maxRead > len(b) {
maxRead = len(b)
}
n, err := rand.Read(b[:maxRead])
r.iter += maxRead
return n, err
}
func (r *customReader) Close() error {
// Uncomment this for even more races :((
// r.iter = 0
return nil
}
func (r *customReader) Reset() {
r.iter = 0
}
func second(w http.ResponseWriter, r *http.Request) {
ioutil.ReadAll(r.Body)
}
func first(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "http://"+addr2+"/second", http.StatusTemporaryRedirect)
}
func main() {
mux1 := http.NewServeMux()
mux1.HandleFunc("/first", first)
srv1 := http.Server{
Addr: addr1,
Handler: mux1,
}
go func() {
err := srv1.ListenAndServe()
fmt.Printf("err: %v", err)
}()
mux2 := http.NewServeMux()
mux2.HandleFunc("/second", second)
srv2 := http.Server{
Addr: addr2,
Handler: mux2,
}
go func() {
err := srv2.ListenAndServe()
fmt.Printf("err: %v", err)
}()
time.Sleep(time.Second)
client := http.DefaultClient
wg := &sync.WaitGroup{}
for i := 0; i < 1000; i++ {
reader := &customReader{size: 900000}
wg.Add(1)
go func(r *customReader) {
for {
req, err := http.NewRequest(http.MethodPut, "http://"+addr1+"/first", r)
if err != nil {
fmt.Printf("%v", err)
}
req.GetBody = func() (io.ReadCloser, error) {
return &customReader{size: 900000}, nil
}
if resp, err := client.Do(req); err != nil {
// fmt.Printf("error: %v", err)
} else if resp.StatusCode >= http.StatusBadRequest {
// fmt.Printf("status code: %d", resp.StatusCode)
}
// Reset reader and try to reuse it in next request
r.Reset()
}
wg.Done()
}(reader)
}
wg.Wait() // infinite wait
srv1.Close()
srv2.Close()
}
What did you expect to see?
No races
What did you see instead?
Races:
==================
WARNING: DATA RACE
Write at 0x00c0003e00a0 by goroutine 87:
main.main.func3()
/home/januszm/concept.go:43 +0x55
Previous write at 0x00c0003e00a0 by goroutine 3899:
[failed to restore the stack]
Goroutine 87 (running) created at:
main.main()
/home/januszm/concept.go:91 +0x3b0
Goroutine 3899 (finished) created at:
net/http.(*Transport).dialConn()
/usr/local/go/src/net/http/transport.go:1358 +0xb89
net/http.(*Transport).getConn.func4()
/usr/local/go/src/net/http/transport.go:1015 +0xd0
==================
==================
WARNING: DATA RACE
Write at 0x00c0002ca750 by goroutine 488:
main.main.func3()
/home/januszm/concept.go:43 +0x55
Previous write at 0x00c0002ca750 by goroutine 1951:
main.(*customReader).Read()
/home/januszm/concept.go:33 +0x156
net/http.transferBodyReader.Read()
/usr/local/go/src/net/http/transfer.go:62 +0x77
io.copyBuffer()
/usr/local/go/src/io/io.go:402 +0x143
net/http.(*transferWriter).writeBody()
/usr/local/go/src/io/io.go:364 +0x76e
net/http.(*Request).write()
/usr/local/go/src/net/http/request.go:655 +0x7c3
net/http.(*persistConn).writeLoop()
/usr/local/go/src/net/http/transport.go:1961 +0x321
Goroutine 488 (running) created at:
main.main()
/home/januszm/concept.go:91 +0x3b0
Goroutine 1951 (running) created at:
net/http.(*Transport).dialConn()
/usr/local/go/src/net/http/transport.go:1358 +0xb89
net/http.(*Transport).getConn.func4()
/usr/local/go/src/net/http/transport.go:1015 +0xd0
==================
==================
WARNING: DATA RACE
Write at 0x00c0002ca780 by goroutine 491:
main.main.func3()
/home/januszm/concept.go:43 +0x55
Previous write at 0x00c0002ca780 by goroutine 3360:
??()
-:0 +0xffffffffffffffff
fmt.(*fmt).fmtInteger()
/usr/local/go/src/fmt/format.go:307 +0x441
fmt.(*pp).fmtInteger()
/usr/local/go/src/fmt/print.go:386 +0x297
fmt.(*pp).printArg()
/usr/local/go/src/fmt/print.go:662 +0xf13
fmt.(*pp).doPrintf()
/usr/local/go/src/fmt/print.go:1016 +0x315
fmt.Fprintf()
/usr/local/go/src/fmt/print.go:199 +0x7f
net/http/internal.(*chunkedWriter).Write()
/usr/local/go/src/net/http/internal/chunked.go:203 +0xd8
io.copyBuffer()
/usr/local/go/src/io/io.go:404 +0x282
net/http.(*transferWriter).writeBody()
/usr/local/go/src/io/io.go:364 +0x76e
net/http.(*Request).write()
/usr/local/go/src/net/http/request.go:655 +0x7c3
net/http.(*persistConn).writeLoop()
/usr/local/go/src/net/http/transport.go:1961 +0x321
Goroutine 491 (running) created at:
main.main()
/home/januszm/concept.go:91 +0x3b0
==================