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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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/[email protected]/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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions