http Flush() causes "panic: runtime error: invalid memory address"

533 views
Skip to first unread message

Fumin Wang

unread,
Nov 1, 2013, 1:47:32 PM11/1/13
to golan...@googlegroups.com
While implementing heartbeats for a long living HTTP connection on the server,
I encountered a panic raised from the http package itself.
There isn't anything fancy in the implementation except for the fact that the response writer
is passed to another goroutine. The code can be found in http://play.golang.org/p/ElC4PpU-6S .
It doesn't run directly on the website, but I made sure it ran locally, and the panic runtime
error is pretty reproducible and predictable.

These two threads suggested that writers not be passed to other goroutines, but I'm not
convinced, since these panics don't occur if
* We don't write on line 14 `w.Write([]byte("hello"))`
* or if we don't provide the extra 100ms margin for the Sleep interval on line 22 `time.Sleep(interval + 100 * time.Millisecond)`

The output of `go version` is "go version go1.1.2 darwin/amd64", and I'm on the latest
Mavericks OS.
Below is a copy of the reproducible code:
```
package main

import (
  "fmt"
  "net/http"
  "time"
)

func handler(w http.ResponseWriter, r *http.Request) {
  interval := 1 * time.Second
  ticker := time.NewTicker(interval)
  go func() {
    for _ = range ticker.C {
      w.Write([]byte("hello"))
      if f, ok := w.(http.Flusher); ok {
        fmt.Println("flush")
        f.Flush()
      }
    }
  }()

  time.Sleep(interval + 100 * time.Millisecond)
}

func startServer() {
  http.HandleFunc("/", handler)
  go func() {
    http.ListenAndServe(":8080", nil)
  }()
}

func main() {
  startServer()
  http.Get("http://localhost:8080/")
  time.Sleep(1 * time.Minute)
}
```

Here's the stack trace:
```

panic: runtime error: invalid memory address or nil pointer dereference

[signal 0xb code=0x1 addr=0x20 pc=0x5391c]


goroutine 10 [running]:

net/http.(*switchWriter).Write(0xc200078790, 0xc2000e9800, 0x5, 0x800, 0x0, ...)

/usr/local/go/src/pkg/net/http/chunked.go:0 +0x5c

bufio.(*Writer).Flush(0xc200095b80, 0xc20009c420, 0xc200000008)

/usr/local/go/src/pkg/bufio/bufio.go:465 +0x14a

net/http.(*response).Flush(0xc2000b3700)

/usr/local/go/src/pkg/net/http/server.go:952 +0x4a

main.func·001()

/tmp/ab.go:17 +0x1e2

created by main.handler

/tmp/ab.go:20 +0xac

```

minux

unread,
Nov 1, 2013, 2:03:49 PM11/1/13
to Fumin Wang, golang-nuts

when the handler returned, the goroutine shouldn't do any operation on it anymore.

DisposaBoy

unread,
Nov 1, 2013, 2:07:15 PM11/1/13
to golan...@googlegroups.com
TL;DR you're returning from the handler... and then writing to the responsewriter. sorry I don't know how else to explain it .

Fumin Wang

unread,
Nov 1, 2013, 2:12:58 PM11/1/13
to golan...@googlegroups.com
Right, thanks for your observations, that resonates with what's being said in https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/vzVgBwJ1q2c/jCS_twDIScAJ

I wonder are you able to answer these further questions? 
* Why abruptly panic with a runtime error instead of an error return value which is the standard way of reporting errors?
* Why isn't the error raised in the earlier Write `w.Write([]byte("hello"))` but only in the Flush? 

minux

unread,
Nov 1, 2013, 2:16:47 PM11/1/13
to Fumin Wang, golang-nuts


On Nov 1, 2013 2:13 PM, "Fumin Wang" <awaw...@gmail.com> wrote:
>
> Right, thanks for your observations, that resonates with what's being said in https://groups.google.com/forum/#!searchin/golang-nuts/http$20flush/golang-nuts/vzVgBwJ1q2c/jCS_twDIScAJ
>
> I wonder are you able to answer these further questions? 
> * Why abruptly panic with a runtime error instead of an error return value which is the standard way of reporting errors?

checking that every method call on responsewriter is valid will slow everything down.

besides panic for programmer error is also an idiom for Go.


> * Why isn't the error raised in the earlier Write `w.Write([]byte("hello"))` but only in the Flush? 

i'd say this is implementation detail so you'd better read the source code to find it out yourself.

Reply all
Reply to author
Forward
0 new messages