Skip to content

net/http or io: panic (reduced test case included) #7848

@olov

Description

@olov
What does 'go version' print?
o version go1.2 darwin/amd64

server.go:
package main

import (
    "io"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello World\n")
    })
    http.ListenAndServe(":8100", nil)
}


crashproxy.go:
package main

import (
    "net/http"
    "net/http/httputil"
    "net/url"
)

func main() {
    server, _ := url.Parse("http://127.0.0.1:8100";)
    http.Handle("/", httputil.NewSingleHostReverseProxy(server))
    http.ListenAndServe(":11111", nil)
}


% go run server.go &
% go build crashproxy.go # we need the executable below
% ./crashproxy


With these running, we'll POST a file to the hello server through the reverse proxy.
We'll send the crashproxy binary (5-10 MBs).

% curl -i -F "file=@crashproxy;filename=crashproxy" http://localhost:11111

Run that curl command a number of times (drum arrow-up / enter quickly) until crashproxy
panics. I believe the crash is unrelated to the reverse proxy code but it was easier to
demonstrate using it.

[My real-world code that triggered this panic had a (node.js) server process that
sometimes crashed (upon file POST) and then sometimes took a (golang) reverse proxy with
it. This test case doesn't feature a crashing server process because one that just
responded directly seemed to do the trick as well]

Panic log follows:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x20 pc=0x518c0]

goroutine 40 [running]:
runtime.panic(0x1f8d60, 0x476df9)
    /usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
bufio.(*Reader).Read(0xc210037660, 0xc2100ca000, 0x1000, 0x1000, 0x1000, ...)
    /usr/local/go/src/pkg/bufio/bufio.go:152 +0x100
io.(*LimitedReader).Read(0xc2100a8ee0, 0xc2100ca000, 0x1000, 0x1000, 0x1000, ...)
    /usr/local/go/src/pkg/io/io.go:398 +0xbb
net/http.(*body).Read(0xc2100c7030, 0xc2100ca000, 0x1000, 0x1000, 0x1000, ...)
    /usr/local/go/src/pkg/net/http/transfer.go:534 +0x96
net/http.(*expectContinueReader).Read(0xc2100a8f00, 0xc2100ca000, 0x1000, 0x1000,
0xc2100ca000, ...)
    /usr/local/go/src/pkg/net/http/server.go:520 +0x11a
io.(*LimitedReader).Read(0xc2100a8060, 0xc2100ca000, 0x1000, 0x1000, 0xbf, ...)
    /usr/local/go/src/pkg/io/io.go:398 +0xbb
bufio.(*Writer).ReadFrom(0xc21004e4c0, 0x55f458, 0xc2100a8060, 0xa6ed1, 0x0, ...)
    /usr/local/go/src/pkg/bufio/bufio.go:622 +0x15a
io.Copy(0x55f588, 0xc21004e4c0, 0x55f458, 0xc2100a8060, 0x0, ...)
    /usr/local/go/src/pkg/io/io.go:348 +0x124
net/http.(*transferWriter).WriteBody(0xc2100c62a0, 0x55f588, 0xc21004e4c0, 0x0, 0x0)
    /usr/local/go/src/pkg/net/http/transfer.go:196 +0x57c
net/http.(*Request).write(0xc2100361a0, 0x55f588, 0xc21004e4c0, 0x0, 0xc2100c7150, ...)
    /usr/local/go/src/pkg/net/http/request.go:400 +0x7e4
net/http.(*persistConn).writeLoop(0xc210058780)
    /usr/local/go/src/pkg/net/http/transport.go:797 +0x185
created by net/http.(*Transport).dialConn
    /usr/local/go/src/pkg/net/http/transport.go:529 +0x61e

goroutine 1 [IO wait]:
net.runtime_pollWait(0x55f300, 0x72, 0x0)
    /private/tmp/bindist142506725/go/src/pkg/runtime/netpoll.goc:116 +0x6a
net.(*pollDesc).Wait(0xc21004f140, 0x72, 0x55e098, 0x23)
    /usr/local/go/src/pkg/net/fd_poll_runtime.go:81 +0x34
net.(*pollDesc).WaitRead(0xc21004f140, 0x23, 0x55e098)
    /usr/local/go/src/pkg/net/fd_poll_runtime.go:86 +0x30
net.(*netFD).accept(0xc21004f0e0, 0x2a8fb8, 0x0, 0x55e098, 0x23)
    /usr/local/go/src/pkg/net/fd_unix.go:382 +0x2c2
net.(*TCPListener).AcceptTCP(0xc2100001e0, 0x3760b, 0x59ee10, 0x3760b)
    /usr/local/go/src/pkg/net/tcpsock_posix.go:233 +0x47
net.(*TCPListener).Accept(0xc2100001e0, 0x55f3a8, 0xc210000aa0, 0xc210058580, 0x0)
    /usr/local/go/src/pkg/net/tcpsock_posix.go:243 +0x27
net/http.(*Server).Serve(0xc21001e410, 0x55e360, 0xc2100001e0, 0x0, 0x0)
    /usr/local/go/src/pkg/net/http/server.go:1622 +0x91
net/http.(*Server).ListenAndServe(0xc21001e410, 0xc21001e410, 0xc21004b4a0)
    /usr/local/go/src/pkg/net/http/server.go:1612 +0xa0
net/http.ListenAndServe(0x237c00, 0x6, 0x0, 0x0, 0x0, ...)
    /usr/local/go/src/pkg/net/http/server.go:1677 +0x6d
main.main()
    /Users/olov/projects/mcs/goproxy/src/crashproxy.go:12 +0xad

goroutine 3 [IO wait]:
net.runtime_pollWait(0x55f258, 0x72, 0x0)
    /private/tmp/bindist142506725/go/src/pkg/runtime/netpoll.goc:116 +0x6a
net.(*pollDesc).Wait(0xc21004f300, 0x72, 0x55e098, 0x23)
    /usr/local/go/src/pkg/net/fd_poll_runtime.go:81 +0x34
net.(*pollDesc).WaitRead(0xc21004f300, 0x23, 0x55e098)
    /usr/local/go/src/pkg/net/fd_poll_runtime.go:86 +0x30
net.(*netFD).Read(0xc21004f2a0, 0xc21005a000, 0x1000, 0x1000, 0x0, ...)
    /usr/local/go/src/pkg/net/fd_unix.go:204 +0x2a0
net.(*conn).Read(0xc210000200, 0xc21005a000, 0x1000, 0x1000, 0x0, ...)
    /usr/local/go/src/pkg/net/net.go:122 +0xc5
net/http.(*liveSwitchReader).Read(0xc2100582a8, 0xc21005a000, 0x1000, 0x1000, 0x5bab48,
...)
    /usr/local/go/src/pkg/net/http/server.go:204 +0xa5
io.(*LimitedReader).Read(0xc21004b4e0, 0xc21005a000, 0x1000, 0x1000, 0xb434, ...)
    /usr/local/go/src/pkg/io/io.go:398 +0xbb
bufio.(*Reader).fill(0xc2100370c0)
    /usr/local/go/src/pkg/bufio/bufio.go:91 +0x110
bufio.(*Reader).ReadSlice(0xc2100370c0, 0xa, 0x0, 0x0, 0x0, ...)
    /usr/local/go/src/pkg/bufio/bufio.go:274 +0x204
bufio.(*Reader).ReadLine(0xc2100370c0, 0x0, 0x0, 0x0, 0x0, ...)
    /usr/local/go/src/pkg/bufio/bufio.go:305 +0x63
net/textproto.(*Reader).readLineSlice(0xc21001da50, 0x555000, 0x199fe0, 0x5bace8,
0x20752, ...)
    /usr/local/go/src/pkg/net/textproto/reader.go:55 +0x61
net/textproto.(*Reader).ReadLine(0xc21001da50, 0xc2100441a0, 0x0, 0xc21005b000, 0x0)
    /usr/local/go/src/pkg/net/textproto/reader.go:36 +0x27
net/http.ReadRequest(0xc2100370c0, 0xc2100441a0, 0x0, 0x0)
    /usr/local/go/src/pkg/net/http/request.go:526 +0x88
net/http.(*conn).readRequest(0xc210058280, 0x0, 0x0, 0x0)
    /usr/local/go/src/pkg/net/http/server.go:575 +0x1bb
net/http.(*conn).serve(0xc210058280)
    /usr/local/go/src/pkg/net/http/server.go:1123 +0x3b4
created by net/http.(*Server).Serve
    /usr/local/go/src/pkg/net/http/server.go:1644 +0x28b

goroutine 33 [sleep]:
time.Sleep(0x1dcd6500)
    /private/tmp/bindist142506725/go/src/pkg/runtime/time.goc:31 +0x31
net/http.(*conn).closeWriteAndWait(0xc210058480)
    /usr/local/go/src/pkg/net/http/server.go:1072 +0x75
net/http.(*conn).serve(0xc210058480)
    /usr/local/go/src/pkg/net/http/server.go:1174 +0x81d
created by net/http.(*Server).Serve
    /usr/local/go/src/pkg/net/http/server.go:1644 +0x28b

goroutine 37 [sleep]:
time.Sleep(0x1dcd6500)
    /private/tmp/bindist142506725/go/src/pkg/runtime/time.goc:31 +0x31
net/http.(*conn).closeWriteAndWait(0xc210058580)
    /usr/local/go/src/pkg/net/http/server.go:1072 +0x75
net/http.(*conn).serve(0xc210058580)
    /usr/local/go/src/pkg/net/http/server.go:1174 +0x81d
created by net/http.(*Server).Serve
    /usr/local/go/src/pkg/net/http/server.go:1644 +0x28b
exit status 2

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions