Skip to content

Composed decode hooks may panic while decoding ,remain data #121

@ZoeySimone

Description

@ZoeySimone

When composing multiple decoding hooks with DecodeNil set and using the mapstructure:",remain" tag it is possible to trigger a panic in mapstructure.

Minimal reproduction code

func main() {
	v := make(map[string]any)
	v["m"] = nil

	var result struct {
		V map[string]any `mapstructure:",remain"`
	}

	hook := func(f reflect.Kind, t reflect.Kind, data any) (any, error) {
		return data, nil
	}

	dec, _ := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
		DecodeHook: mapstructure.ComposeDecodeHookFunc(
			hook, hook,
		),
		DecodeNil: true,
		Result:    &result,
	})

	dec.Decode(&v)

	fmt.Printf("%+v\n", result)
}

Output

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

goroutine 1 [running]:
reflect.valueInterface({0x0?, 0x0?, 0x0?}, 0x0?)
        /opt/homebrew/Cellar/go/1.24.0/libexec/src/reflect/value.go:1486 +0xfc
reflect.Value.Interface(...)
        /opt/homebrew/Cellar/go/1.24.0/libexec/src/reflect/value.go:1481
github.com/go-viper/mapstructure/v2.cachedDecodeHook.func2({0x0?, 0x0?, 0x10272cfe0?}, {0x1027324e0?, 0x1400012c120?, 0x1026ecaa0?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/decode_hooks.go:51 +0x50
github.com/go-viper/mapstructure/v2.ComposeDecodeHookFunc.func1({0x1027324e0?, 0x1028295e0?, 0x14000146f68?}, {0x1027324e0?, 0x1400012c120?, 0x10296fac8?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/decode_hooks.go:99 +0xc0
github.com/go-viper/mapstructure/v2.cachedDecodeHook.func3({0x1027324e0?, 0x1028295e0?, 0x14000146fb8?}, {0x1027324e0?, 0x1400012c120?, 0x102688338?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/decode_hooks.go:55 +0x34
github.com/go-viper/mapstructure/v2.(*Decoder).decode(0x1400012c0b0, {0x14000116030, 0x16}, {0x0, 0x0}, {0x1027324e0?, 0x1400012c120?, 0x10271d234?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:532 +0x498
github.com/go-viper/mapstructure/v2.(*Decoder).decodeMapFromMap(0x1400012c0b0, {0x0, 0x0}, {0x102736600?, 0x14000112300?, 0x102736600?}, {0x102736580?, 0x1400010c048?, 0x14000147298?}, {0x102736580?, ...})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:1029 +0x4ec
github.com/go-viper/mapstructure/v2.(*Decoder).decodeMap(0x1400012c0b0, {0x0, 0x0}, {0x102736600, 0x14000112300}, {0x102736580?, 0x1400010c048?, 0x0?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:955 +0x28c
github.com/go-viper/mapstructure/v2.(*Decoder).decodeStructFromMap(0x1400012c0b0, {0x0, 0x0}, {0x102736580?, 0x1400010c040?, 0x195?}, {0x102736200?, 0x1400010c048?, 0x199?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:1592 +0x13d4
github.com/go-viper/mapstructure/v2.(*Decoder).decodeStruct(0x1400012c0b0, {0x0, 0x0}, {0x10272a900?, 0x1400010c040?}, {0x102736200?, 0x1400010c048?, 0x1026e0efc?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:1388 +0x438
github.com/go-viper/mapstructure/v2.(*Decoder).decode(0x1400012c0b0, {0x0, 0x0}, {0x10272a900, 0x1400010c040}, {0x102736200?, 0x1400010c048?, 0x1026ec720?})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:559 +0x71c
github.com/go-viper/mapstructure/v2.(*Decoder).Decode(0x1400012c0b0, {0x10272a900, 0x1400010c040})
        /Users/zoey/go/pkg/mod/github.com/go-viper/mapstructure/v2@v2.4.0/mapstructure.go:461 +0xb4
main.main()
        /Users/zoey/repos/jsonerrorstest/main.go:156 +0x150
exit status 2

In ComposeDecodeHookFunc the value of f reflect.Value may have f.Kind() == reflect.Interface and f.IsNil() == true, performing reflect.ValueOf() on f with these properties results in an invalid reflect.Value.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions