Repository: mitchellh/mapstructure
Pull request #265 (2021-12-23 03:26:31)

fix: panic when Decode's input is array and output is a slice
Close https://github.com/mitchellh/mapstructure/issues/264

## Test

I have confirmed the issue is reproduced by 74cdd45

```console
$ go test -race -run Decode_decodeSliceWithArray ./...
--- FAIL: TestDecode_decodeSliceWithArray (0.00s)
    --- FAIL: TestDecode_decodeSliceWithArray/input_is_array (0.00s)
panic: reflect: call of reflect.Value.IsNil on array Value [recovered]
	panic: reflect: call of reflect.Value.IsNil on array Value

goroutine 20 [running]:
testing.tRunner.func1.2({0x1237e60, 0xc0001b21b0})
	/usr/local/Cellar/go/1.17.5/libexec/src/testing/testing.go:1209 +0x36c
testing.tRunner.func1()
	/usr/local/Cellar/go/1.17.5/libexec/src/testing/testing.go:1212 +0x3b6
panic({0x1237e60, 0xc0001b21b0})
	/usr/local/Cellar/go/1.17.5/libexec/src/runtime/panic.go:1047 +0x266
reflect.Value.IsNil(...)
	/usr/local/Cellar/go/1.17.5/libexec/src/reflect/value.go:1427
github.com/mitchellh/mapstructure.(*Decoder).decodeSlice(0xc0001a4048, {0x0, 0x0}, {0x1233220, 0x13b9f68}, {0x1230140, 0xc0001b2180, 0x9ca1ed8})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:1092 +0xfd1
github.com/mitchellh/mapstructure.(*Decoder).decode(0xc0001a4048, {0x0, 0x2880008}, {0x1233220, 0x13b9f68}, {0x1230140, 0xc0001b2180, 0x10aa9bb})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:469 +0x815
github.com/mitchellh/mapstructure.(*Decoder).decodePtr(0xc0001a4048, {0x0, 0x0}, {0x1233220, 0x13b9f68}, {0xc0001e06c0, 0xc0001b2180, 0x1230140})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:1031 +0x73b
github.com/mitchellh/mapstructure.(*Decoder).decode(0xc0001a4048, {0x0, 0x8}, {0x1233220, 0x13b9f68}, {0xc0001e06c0, 0xc0001b2180, 0xc0001a62a0})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:467 +0x630
github.com/mitchellh/mapstructure.(*Decoder).decodeBasic(0x1078872, {0x0, 0x0}, {0x1233220, 0x13b9f68}, {0x1236aa0, 0xc0001e06a0, 0x12313e0})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:513 +0x63f
github.com/mitchellh/mapstructure.(*Decoder).decode(0xc0001a4048, {0x0, 0x3636000009ca2f50}, {0x1233220, 0x13b9f68}, {0x1236aa0, 0xc0001e06a0, 0xc00018e1d0})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:453 +0x67b
github.com/mitchellh/mapstructure.(*Decoder).Decode(0xc0001a4048, {0x1233220, 0x13b9f68})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:398 +0x1dd
github.com/mitchellh/mapstructure.Decode({0x1233220, 0x13b9f68}, {0x122cdc0, 0xc0001e06a0})
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure.go:302 +0x151
github.com/mitchellh/mapstructure.TestDecode_decodeSliceWithArray.func1(0xc000183a00)
	/Users/shunsuke-suzuki/repos/src/github.com/mitchellh/mapstructure/mapstructure_test.go:580 +0x87
testing.tRunner(0xc000183a00, 0xc00019ad60)
	/usr/local/Cellar/go/1.17.5/libexec/src/testing/testing.go:1259 +0x230
created by testing.(*T).Run
	/usr/local/Cellar/go/1.17.5/libexec/src/testing/testing.go:1306 +0x727
FAIL	github.com/mitchellh/mapstructure	0.246s
FAIL
```

And the issue is solved by ab94595

```console
$ go test -race -run Decode_decodeSliceWithArray ./...
ok  	github.com/mitchellh/mapstructure	0.245s
```


Patch:
diff --git a/mapstructure.go b/mapstructure.go
index 6b81b00..d6b01f7 100644
--- a/mapstructure.go
+++ b/mapstructure.go
@@ -1088,7 +1088,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
 	}
 
 	// If the input value is nil, then don't allocate since empty != nil
-	if dataVal.IsNil() {
+	if dataValKind != reflect.Array && dataVal.IsNil() {
 		return nil
 	}
 


Test patch:
diff --git a/mapstructure_test.go b/mapstructure_test.go
index a78e77a..e4ba428 100644
--- a/mapstructure_test.go
+++ b/mapstructure_test.go
@@ -556,6 +556,38 @@ func TestDecode_EmbeddedArray(t *testing.T) {
 	}
 }
 
+func TestDecode_decodeSliceWithArray(t *testing.T) {
+	t.Parallel()
+
+	data := []struct {
+		title  string
+		input  interface{}
+		result interface{}
+		exp    interface{}
+	}{
+		{
+			title:  "input is array and result is slice",
+			input:  [1]int{1},
+			result: []int{},
+			exp:    []int{1},
+		},
+	}
+
+	for _, d := range data {
+		d := d
+		t.Run(d.title, func(t *testing.T) {
+			t.Parallel()
+			if err := Decode(d.input, &d.result); err != nil {
+				t.Fatalf("got an err: %s", err.Error())
+			}
+
+			if !reflect.DeepEqual(d.exp, d.result) {
+				t.Errorf("wanted %+v, got %+v", d.exp, d.result)
+			}
+		})
+	}
+}
+
 func TestDecode_EmbeddedNoSquash(t *testing.T) {
 	t.Parallel()