diff --git a/builtins.go b/builtins.go index f64788fc..9cf0f8be 100644 --- a/builtins.go +++ b/builtins.go @@ -1734,7 +1734,10 @@ func tomlAddToPath(path []string, tail string) []string { } // tomlRenderValue returns a rendered value as string, with proper indenting -func tomlRenderValue(i *interpreter, val value, sindent string, indexedPath []string, inline bool, cindent string) (string, error) { +func tomlRenderValue(i *interpreter, val value, sindent string, indexedPath []string, inline bool, cindent string, depth int) (string, error) { + if depth <= 0 { + return "", i.Error("max manifest depth exceeded, possible infinite recursion") + } switch v := val.(type) { case *valueNull: return "", i.Error(fmt.Sprintf("Tried to manifest \"null\" at %v", indexedPath)) @@ -1776,7 +1779,7 @@ func tomlRenderValue(i *interpreter, val value, sindent string, indexedPath []st } res = res + newIndent - value, err := tomlRenderValue(i, thunkValue, sindent, childIndexedPath, true, "") + value, err := tomlRenderValue(i, thunkValue, sindent, childIndexedPath, true, "", depth-1) if err != nil { return "", err } @@ -1807,7 +1810,7 @@ func tomlRenderValue(i *interpreter, val value, sindent string, indexedPath []st childIndexedPath := tomlAddToPath(indexedPath, fieldName) - value, err := tomlRenderValue(i, fieldValue, sindent, childIndexedPath, true, "") + value, err := tomlRenderValue(i, fieldValue, sindent, childIndexedPath, true, "", depth-1) if err != nil { return "", err } @@ -1825,7 +1828,10 @@ func tomlRenderValue(i *interpreter, val value, sindent string, indexedPath []st } } -func tomlRenderTableArray(i *interpreter, v *valueArray, sindent string, path []string, indexedPath []string, cindent string) (string, error) { +func tomlRenderTableArray(i *interpreter, v *valueArray, sindent string, path []string, indexedPath []string, cindent string, depth int) (string, error) { + if depth <= 0 { + return "", i.Error("max manifest depth exceeded, possible infinite recursion") + } sections := make([]string, 0, len(v.elements)) @@ -1858,7 +1864,7 @@ func tomlRenderTableArray(i *interpreter, v *valueArray, sindent string, path [] childIndexedPath := tomlAddToPath(indexedPath, strconv.FormatInt(int64(j), 10)) // render the table and add it to result - table, err := tomlTableInternal(i, tv, sindent, path, childIndexedPath, cindent+sindent) + table, err := tomlTableInternal(i, tv, sindent, path, childIndexedPath, cindent+sindent, depth-1) if err != nil { return "", err } @@ -1874,7 +1880,10 @@ func tomlRenderTableArray(i *interpreter, v *valueArray, sindent string, path [] return strings.Join(sections, "\n\n"), nil } -func tomlRenderTable(i *interpreter, v *valueObject, sindent string, path []string, indexedPath []string, cindent string) (string, error) { +func tomlRenderTable(i *interpreter, v *valueObject, sindent string, path []string, indexedPath []string, cindent string, depth int) (string, error) { + if depth <= 0 { + return "", i.Error("max manifest depth exceeded, possible infinite recursion") + } res := cindent + "[" for i, element := range path { if i > 0 { @@ -1887,7 +1896,7 @@ func tomlRenderTable(i *interpreter, v *valueObject, sindent string, path []stri res = res + "\n" } - table, err := tomlTableInternal(i, v, sindent, path, indexedPath, cindent+sindent) + table, err := tomlTableInternal(i, v, sindent, path, indexedPath, cindent+sindent, depth-1) if err != nil { return "", err } @@ -1896,7 +1905,10 @@ func tomlRenderTable(i *interpreter, v *valueObject, sindent string, path []stri return res, nil } -func tomlTableInternal(i *interpreter, v *valueObject, sindent string, path []string, indexedPath []string, cindent string) (string, error) { +func tomlTableInternal(i *interpreter, v *valueObject, sindent string, path []string, indexedPath []string, cindent string, depth int) (string, error) { + if depth <= 0 { + return "", i.Error("max manifest depth exceeded, possible infinite recursion") + } resFields := []string{} resSections := []string{""} fields := objectFields(v, withoutHidden) @@ -1923,13 +1935,13 @@ func tomlTableInternal(i *interpreter, v *valueObject, sindent string, path []st switch fv := fieldValue.(type) { case *valueObject: - section, err := tomlRenderTable(i, fv, sindent, childPath, childIndexedPath, cindent) + section, err := tomlRenderTable(i, fv, sindent, childPath, childIndexedPath, cindent, depth-1) if err != nil { return "", err } resSections = append(resSections, section) case *valueArray: - section, err := tomlRenderTableArray(i, fv, sindent, childPath, childIndexedPath, cindent) + section, err := tomlRenderTableArray(i, fv, sindent, childPath, childIndexedPath, cindent, depth-1) if err != nil { return "", err } @@ -1940,7 +1952,7 @@ func tomlTableInternal(i *interpreter, v *valueObject, sindent string, path []st } else { // render as value and append to result fields - renderedValue, err := tomlRenderValue(i, fieldValue, sindent, childIndexedPath, false, "") + renderedValue, err := tomlRenderValue(i, fieldValue, sindent, childIndexedPath, false, "", depth-1) if err != nil { return "", err } @@ -1968,7 +1980,7 @@ func builtinManifestTomlEx(i *interpreter, arguments []value) (value, error) { switch v := val.(type) { case *valueObject: - res, err := tomlTableInternal(i, v, sindent, []string{}, []string{}, "") + res, err := tomlTableInternal(i, v, sindent, []string{}, []string{}, "", i.stack.limit) if err != nil { return nil, err } @@ -2006,8 +2018,11 @@ func builtinManifestJSONEx(i *interpreter, arguments []value) (value, error) { var path []string - var aux func(ov value, path []string, cindent string) (string, error) - aux = func(ov value, path []string, cindent string) (string, error) { + var aux func(ov value, path []string, cindent string, depth int) (string, error) + aux = func(ov value, path []string, cindent string, depth int) (string, error) { + if depth <= 0 { + return "", i.Error("max manifest depth exceeded, possible infinite recursion") + } if ov == nil { fmt.Println("value is nil") return "null", nil @@ -2040,7 +2055,7 @@ func builtinManifestJSONEx(i *interpreter, arguments []value) (value, error) { } newPath := append(path, strconv.FormatInt(int64(aI), 10)) - s, err := aux(cTv, newPath, newIndent) + s, err := aux(cTv, newPath, newIndent, depth-1) if err != nil { return "", err } @@ -2068,7 +2083,7 @@ func builtinManifestJSONEx(i *interpreter, arguments []value) (value, error) { } newPath := append(path, fieldName) - mvs, err := aux(fieldValue, newPath, newIndent) + mvs, err := aux(fieldValue, newPath, newIndent, depth-1) if err != nil { return "", err } @@ -2084,7 +2099,7 @@ func builtinManifestJSONEx(i *interpreter, arguments []value) (value, error) { } } - finalString, err := aux(val, path, "") + finalString, err := aux(val, path, "", i.stack.limit) if err != nil { return nil, err } @@ -2172,8 +2187,11 @@ func builtinManifestYamlDoc(i *interpreter, arguments []value) (value, error) { var buf bytes.Buffer - var aux func(ov value, buf *bytes.Buffer, cindent string) error - aux = func(ov value, buf *bytes.Buffer, cindent string) error { + var aux func(ov value, buf *bytes.Buffer, cindent string, depth int) error + aux = func(ov value, buf *bytes.Buffer, cindent string, depth int) error { + if depth <= 0 { + return i.Error("max manifest depth exceeded, possible infinite recursion") + } switch v := ov.(type) { case *valueNull: buf.WriteString("null") @@ -2231,7 +2249,7 @@ func builtinManifestYamlDoc(i *interpreter, arguments []value) (value, error) { cindent = cindent + yamlIndent } - if err := aux(thunkValue, buf, cindent); err != nil { + if err := aux(thunkValue, buf, cindent, depth-1); err != nil { return err } cindent = prevIndent @@ -2281,7 +2299,7 @@ func builtinManifestYamlDoc(i *interpreter, arguments []value) (value, error) { } else { buf.WriteByte(' ') } - if err := aux(fieldValue, buf, cindent); err != nil { + if err := aux(fieldValue, buf, cindent, depth-1); err != nil { return err } cindent = prevIndent @@ -2290,7 +2308,7 @@ func builtinManifestYamlDoc(i *interpreter, arguments []value) (value, error) { return nil } - if err := aux(val, &buf, ""); err != nil { + if err := aux(val, &buf, "", i.stack.limit); err != nil { return nil, err } diff --git a/testdata/builtinManifestJsonEx_cyclic.golden b/testdata/builtinManifestJsonEx_cyclic.golden new file mode 100644 index 00000000..ae330728 --- /dev/null +++ b/testdata/builtinManifestJsonEx_cyclic.golden @@ -0,0 +1,10 @@ +RUNTIME ERROR: max manifest depth exceeded, possible infinite recursion +------------------------------------------------- + testdata/builtinManifestJsonEx_cyclic:1:1-32 $ + +std.manifestJsonEx({a: $}, " ") + +------------------------------------------------- + During evaluation + + diff --git a/testdata/builtinManifestJsonEx_cyclic.jsonnet b/testdata/builtinManifestJsonEx_cyclic.jsonnet new file mode 100644 index 00000000..941de4bb --- /dev/null +++ b/testdata/builtinManifestJsonEx_cyclic.jsonnet @@ -0,0 +1 @@ +std.manifestJsonEx({a: $}, " ") diff --git a/testdata/builtinManifestJsonEx_cyclic.linter.golden b/testdata/builtinManifestJsonEx_cyclic.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtin_manifestTomlEx_cyclic.golden b/testdata/builtin_manifestTomlEx_cyclic.golden new file mode 100644 index 00000000..a212c8c9 --- /dev/null +++ b/testdata/builtin_manifestTomlEx_cyclic.golden @@ -0,0 +1,10 @@ +RUNTIME ERROR: max manifest depth exceeded, possible infinite recursion +------------------------------------------------- + testdata/builtin_manifestTomlEx_cyclic:1:1-37 $ + +std.manifestTomlEx({a: {b: $}}, " ") + +------------------------------------------------- + During evaluation + + diff --git a/testdata/builtin_manifestTomlEx_cyclic.jsonnet b/testdata/builtin_manifestTomlEx_cyclic.jsonnet new file mode 100644 index 00000000..104d8731 --- /dev/null +++ b/testdata/builtin_manifestTomlEx_cyclic.jsonnet @@ -0,0 +1 @@ +std.manifestTomlEx({a: {b: $}}, " ") diff --git a/testdata/builtin_manifestTomlEx_cyclic.linter.golden b/testdata/builtin_manifestTomlEx_cyclic.linter.golden new file mode 100644 index 00000000..e69de29b diff --git a/testdata/builtin_manifestYamlDoc_cyclic.golden b/testdata/builtin_manifestYamlDoc_cyclic.golden new file mode 100644 index 00000000..aaad3837 --- /dev/null +++ b/testdata/builtin_manifestYamlDoc_cyclic.golden @@ -0,0 +1,10 @@ +RUNTIME ERROR: max manifest depth exceeded, possible infinite recursion +------------------------------------------------- + testdata/builtin_manifestYamlDoc_cyclic:1:1-28 $ + +std.manifestYamlDoc({a: $}) + +------------------------------------------------- + During evaluation + + diff --git a/testdata/builtin_manifestYamlDoc_cyclic.jsonnet b/testdata/builtin_manifestYamlDoc_cyclic.jsonnet new file mode 100644 index 00000000..7e793a14 --- /dev/null +++ b/testdata/builtin_manifestYamlDoc_cyclic.jsonnet @@ -0,0 +1 @@ +std.manifestYamlDoc({a: $}) diff --git a/testdata/builtin_manifestYamlDoc_cyclic.linter.golden b/testdata/builtin_manifestYamlDoc_cyclic.linter.golden new file mode 100644 index 00000000..e69de29b