Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to correctly check io.Reader for nil?

If you create a variable of type bytes.Buffer (without initialization) and assign it to a field of type io.Reader, then after checking io.Reader for nil there will be an error: invalid memory address or nil pointer dereference. How to check this correctly to avoid such errors?

Playground

package main

import (
    "bytes"
    "io"
    "io/ioutil"
)

type Request struct {
    Body io.Reader
}

func main() {
    var data *bytes.Buffer

    request := &Request{
        Body: data,
    }

    if request.Body != nil {
        ioutil.ReadAll(request.Body) // panic: runtime error: invalid memory address or nil pointer dereference
    }
}

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

To check if an io.Reader (or any other interface) value is nil, you simply compare it to nil.

Whether a non-nil io.Reader is a meaningful implementation, that’s another question.

E.g. is this implementation meaningful?

type panicReader struct{}

func (panicReader) Read(p []byte) (int, error) {
    panic("foo")
}

panicReader certainly implements io.Reader, but whenever you call its Read() method, it will always panic.

There is bytes.Buffer. A pointer to it implements io.Reader. But calling Buffer.Read() on a nil *bytes.Buffer pointer value will panic. But not because you can’t call methods on nil pointer receivers, but because the implementation of bytes.Buffer.Read() tries to dereference the pointer receiver, and this dereference operation is what causes the panic:

func (b *Buffer) Read(p []byte) (n int, err error) {
    b.lastRead = opInvalid
    if b.empty() {
    // ...
}

You can’t make a general conclusion here. See this io.Reader implementation:

type myBuffer struct{}

var count int

func (*myBuffer) Read(p []byte) (int, error) {
    if len(p) > 0 {
        count++
        if count >= 10 {
            return 0, io.EOF
        }
        p[0] = 'a'
        return 1, nil
    }
    return 0, nil
}

*myBuffer implements io.Reader, and its Read() method does not use the pointer receiver value. What does this mean? You can call Read() on a nil *myBuffer value:

var data *myBuffer

request := &Request{
    Body: data,
}

if request.Body != nil {
    data, err := ioutil.ReadAll(request.Body)
    fmt.Println(string(data), err)
}

This will output (try it on the Go Playground):

aaaaaaaaa <nil>

See related question:

Hiding nil values, understanding why Go fails here

Go reflection with interface embedded in struct – how to detect "real" functions?

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading