From 40a9504600303e80f0b0ef13b0b7e9779209ed98 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 21 Aug 2016 23:44:35 -0700 Subject: [PATCH] fix panic when decoding invalid value structure into struct When decoding an object into a struct where the object structure doesn't match the Go struct structure, the case tested here would panic. This introduces additional checks to guard against the edge case being hit to avoid the panic. The specific checks being added are: if an item being decoded into a struct is a literal type, the item to be decoded must be non-nil in order to use it. This isn't super clear and to be honest I also don't fully understand it but this fixes the problem without introducing any more test failures and without significant code complexity. --- decoder.go | 2 +- decoder_test.go | 34 +++++++++++++++++++ test-fixtures/terraform_variable_invalid.json | 5 +++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test-fixtures/terraform_variable_invalid.json diff --git a/decoder.go b/decoder.go index cfddbf3..a6938fe 100644 --- a/decoder.go +++ b/decoder.go @@ -489,7 +489,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) // the yacc parser would always ensure top-level elements were arrays. The new // parser does not make the same guarantees, thus we need to convert any // top-level literal elements into a list. - if _, ok := node.(*ast.LiteralType); ok { + if _, ok := node.(*ast.LiteralType); ok && item != nil { node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} } diff --git a/decoder_test.go b/decoder_test.go index c074981..b423033 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -328,6 +328,20 @@ func TestDecode_interface(t *testing.T) { }, }, }, + + // Terraform GH-8295 sanity test that basic decoding into + // interface{} works. + { + "terraform_variable_invalid.json", + false, + map[string]interface{}{ + "variable": []map[string]interface{}{ + map[string]interface{}{ + "whatever": "abc123", + }, + }, + }, + }, } for _, tc := range cases { @@ -676,6 +690,26 @@ func TestDecode_structureMap(t *testing.T) { } } +func TestDecode_structureMapInvalid(t *testing.T) { + // Terraform GH-8295 + + type hclVariable struct { + Default interface{} + Description string + Fields []string `hcl:",decodedFields"` + } + + type rawConfig struct { + Variable map[string]*hclVariable + } + + var actual rawConfig + err := Decode(&actual, testReadFile(t, "terraform_variable_invalid.json")) + if err == nil { + t.Fatal("expected error") + } +} + func TestDecode_interfaceNonPointer(t *testing.T) { var value interface{} err := Decode(value, testReadFile(t, "basic_int_string.hcl")) diff --git a/test-fixtures/terraform_variable_invalid.json b/test-fixtures/terraform_variable_invalid.json new file mode 100644 index 0000000..081247e --- /dev/null +++ b/test-fixtures/terraform_variable_invalid.json @@ -0,0 +1,5 @@ +{ + "variable": { + "whatever": "abc123" + } +}