From 0b31450452666da00e55c41699b5c320171e9748 Mon Sep 17 00:00:00 2001
From: zwwhdls <33822635+zwwhdls@users.noreply.github.com>
Date: Wed, 8 Jul 2020 03:26:51 +0800
Subject: [PATCH] [v2] fix stack overflow error in helm template. (#7185)

* fix #6116

Signed-off-by: zwwhdls <zwwhdls@hotmail.com>

* fix another extreme case

Signed-off-by: zwwhdls <zwwhdls@hotmail.com>
---
 pkg/strvals/parser.go      |  12 +++-
 pkg/strvals/parser_test.go | 129 ++++++++++++++++++++++++++++++-------
 2 files changed, 114 insertions(+), 27 deletions(-)

diff --git a/pkg/strvals/parser.go b/pkg/strvals/parser.go
index d0a647c67..41ee0a678 100644
--- a/pkg/strvals/parser.go
+++ b/pkg/strvals/parser.go
@@ -277,12 +277,20 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
 		}
 	case last == '[':
 		// now we have a nested list. Read the index and handle.
-		i, err := t.keyIndex()
+		nextI, err := t.keyIndex()
 		if err != nil {
 			return list, fmt.Errorf("error parsing index: %s", err)
 		}
+		var crtList []interface{}
+		if len(list) > i {
+			// If nested list already exists, take the value of list to next cycle.
+			existed := list[i]
+			if existed != nil {
+				crtList = list[i].([]interface{})
+			}
+		}
 		// Now we need to get the value after the ].
-		list2, err := t.listItem(list, i)
+		list2, err := t.listItem(crtList, nextI)
 		return setIndex(list, i, list2), err
 	case last == '.':
 		// We have a nested object. Send to t.key
diff --git a/pkg/strvals/parser_test.go b/pkg/strvals/parser_test.go
index 5d77aed18..9f7c04137 100644
--- a/pkg/strvals/parser_test.go
+++ b/pkg/strvals/parser_test.go
@@ -382,39 +382,118 @@ func TestParseSet(t *testing.T) {
 }
 
 func TestParseInto(t *testing.T) {
-	got := map[string]interface{}{
-		"outer": map[string]interface{}{
-			"inner1": "overwrite",
-			"inner2": "value2",
+	tests := []struct {
+		input  string
+		input2 string
+		got    map[string]interface{}
+		expect map[string]interface{}
+		err    bool
+	}{
+		{
+			input: "outer.inner1=value1,outer.inner3=value3,outer.inner4=4",
+			got: map[string]interface{}{
+				"outer": map[string]interface{}{
+					"inner1": "overwrite",
+					"inner2": "value2",
+				},
+			},
+			expect: map[string]interface{}{
+				"outer": map[string]interface{}{
+					"inner1": "value1",
+					"inner2": "value2",
+					"inner3": "value3",
+					"inner4": 4,
+				}},
+			err: false,
 		},
-	}
-	input := "outer.inner1=value1,outer.inner3=value3,outer.inner4=4"
-	expect := map[string]interface{}{
-		"outer": map[string]interface{}{
-			"inner1": "value1",
-			"inner2": "value2",
-			"inner3": "value3",
-			"inner4": 4,
+		{
+			input:  "listOuter[0][0].type=listValue",
+			input2: "listOuter[0][0].status=alive",
+			got:    map[string]interface{}{},
+			expect: map[string]interface{}{
+				"listOuter": [][]interface{}{{map[string]string{
+					"type":   "listValue",
+					"status": "alive",
+				}}},
+			},
+			err: false,
+		},
+		{
+			input:  "listOuter[0][0].type=listValue",
+			input2: "listOuter[1][0].status=alive",
+			got:    map[string]interface{}{},
+			expect: map[string]interface{}{
+				"listOuter": [][]interface{}{
+					{
+						map[string]string{"type": "listValue"},
+					},
+					{
+						map[string]string{"status": "alive"},
+					},
+				},
+			},
+			err: false,
+		},
+		{
+			input:  "listOuter[0][1][0].type=listValue",
+			input2: "listOuter[0][0][1].status=alive",
+			got: map[string]interface{}{
+				"listOuter": []interface{}{
+					[]interface{}{
+						[]interface{}{
+							map[string]string{"exited": "old"},
+						},
+					},
+				},
+			},
+			expect: map[string]interface{}{
+				"listOuter": [][][]interface{}{
+					{
+						{
+							map[string]string{"exited": "old"},
+							map[string]string{"status": "alive"},
+						},
+						{
+							map[string]string{"type": "listValue"},
+						},
+					},
+				},
+			},
+			err: false,
 		},
 	}
+	for _, tt := range tests {
+		if err := ParseInto(tt.input, tt.got); err != nil {
+			t.Fatal(err)
+		}
+		if tt.err {
+			t.Errorf("%s: Expected error. Got nil", tt.input)
+		}
 
-	if err := ParseInto(input, got); err != nil {
-		t.Fatal(err)
-	}
+		if tt.input2 != "" {
+			if err := ParseInto(tt.input2, tt.got); err != nil {
+				t.Fatal(err)
+			}
+			if tt.err {
+				t.Errorf("%s: Expected error. Got nil", tt.input2)
+			}
+		}
 
-	y1, err := yaml.Marshal(expect)
-	if err != nil {
-		t.Fatal(err)
-	}
-	y2, err := yaml.Marshal(got)
-	if err != nil {
-		t.Fatalf("Error serializing parsed value: %s", err)
-	}
+		y1, err := yaml.Marshal(tt.expect)
+		if err != nil {
+			t.Fatal(err)
+		}
+		y2, err := yaml.Marshal(tt.got)
+		if err != nil {
+			t.Fatalf("Error serializing parsed value: %s", err)
+		}
 
-	if string(y1) != string(y2) {
-		t.Errorf("%s: Expected:\n%s\nGot:\n%s", input, y1, y2)
+		if string(y1) != string(y2) {
+			t.Errorf("%s: Expected:\n%s\nGot:\n%s", tt.input, y1, y2)
+		}
 	}
 }
+
 func TestParseIntoString(t *testing.T) {
 	got := map[string]interface{}{
 		"outer": map[string]interface{}{
-- 
GitLab