Skip to content

panic: reflect: call of reflect.Value.IsZero on zero Value #46320

@vault-thirteen

Description

@vault-thirteen

What version of Go are you using (go version)?

$ go version
go version go1.16.4 linux/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

Operating System is XUbuntu 20.10 (amd64).
CPU is Intel Xeon E5-2678 v3

GOARCH="amd64"
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/***/.cache/go-build"
GOENV="/home/***/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/***/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/***/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.16.4"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
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-build740936505=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I try to run the IsZero() Method on an Object of reflect.Value Type.
In the Debugger I reach the Code which in Comments is said to be unreachable.

panic: reflect: call of reflect.Value.IsZero on zero Value

goroutine 1 [running]:
reflect.Value.IsZero(0x0, 0x0, 0x0, 0x0)
        /usr/local/go/src/reflect/value.go:1134 +0x70b
// IsZero reports whether v is the zero value for its type.
// It panics if the argument is invalid.
func (v Value) IsZero() bool {
	switch v.kind() {

//...

default:
		// This should never happens, but will act as a safeguard for
		// later, as a default value doesn't makes sense here.
		panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
	}
}

https://play.golang.org/p/o5j2PKXxpwJ

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"reflect"
)

type JsonObject = map[string]interface{}

type ResponseRaw struct {
	Records []JsonObject
}

func main() {
	text := `[{"x": 1, "y": 2}, {"z": 3, "zz": 4, "step": 123}, {}, {"id": 999}, {"q": "test", "lto": {"a": 8, "step": 456}}, null]`
	rr, err := parseValidJson([]byte(text))
	if err != nil {
		log.Println(err)
	}
	fmt.Println("rr:", rr)
}

func parseValidJson(jsonText []byte) (rr *ResponseRaw, err error) {
	responseAnonymous := make([]interface{}, 0)

	err = json.Unmarshal(jsonText, &responseAnonymous)
	if err != nil {
		return nil, err
	}

	rr = &ResponseRaw{
		Records: make([]JsonObject, 0),
	}

	for _, arrayItem := range responseAnonymous {
		arrayItemAsJsonObject, ok := arrayItem.(JsonObject)
		if !ok {
			arrayItemValue := reflect.ValueOf(arrayItem)
			// Here we may receive an empty Value, i.e. reflect.Value{}.
			// When we receive it and check it for Zero Value, we reach that
			// Part of the Code which should be unreachable.
			if arrayItemValue.IsZero() {
				continue
			}
			if arrayItemValue.IsNil() {
				continue
			}
			// The built-in JSON Parser thinks that an empty Object '{}' is an
			// empty Slice of Objects. It may be a Bug in the Parser.
			arrayItemType := reflect.TypeOf(arrayItem)
			if arrayItemType.Kind() == reflect.Slice {
				continue
			}

			return nil, errors.New("json object parsing error")
		}

		rr.Records = append(rr.Records, arrayItemAsJsonObject)
	}

	return rr, nil
}

What did you expect to see?

I expected to see the reflect.Value.IsZero() Method returning a boolean Value.

What did you see instead?

I saw the reflect.Value.IsZero() Method reaching the unreachable code and panicing.

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