diff --git a/decode.go b/decode.go index ab79b22b..038b08b9 100644 --- a/decode.go +++ b/decode.go @@ -309,6 +309,9 @@ type decoder struct { knownFields bool uniqueKeys bool + decodeCount int + aliasCount int + aliasDepth int } var ( @@ -432,6 +435,13 @@ func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field ref } func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) { + d.decodeCount++ + if d.aliasDepth > 0 { + d.aliasCount++ + } + if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > 0.99 { + failf("document contains excessive aliasing") + } if out.Type() == nodeType { out.Set(reflect.ValueOf(n).Elem()) return true @@ -474,7 +484,9 @@ func (d *decoder) alias(n *Node, out reflect.Value) (good bool) { failf("anchor '%s' value contains itself", n.Value) } d.aliases[n] = true + d.aliasDepth++ good = d.unmarshal(n.Alias, out) + d.aliasDepth-- delete(d.aliases, n) return good } diff --git a/decode_test.go b/decode_test.go index 8c6a8e1e..51141eb0 100644 --- a/decode_test.go +++ b/decode_test.go @@ -911,6 +911,18 @@ var unmarshalErrorTests = []struct { {"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`}, {"b: *a\na: &a {c: 1}", `yaml: unknown anchor 'a' referenced`}, {"%TAG !%79! tag:yaml.org,2002:\n---\nv: !%79!int '1'", "yaml: did not find expected whitespace"}, + { + "a: &a [00,00,00,00,00,00,00,00,00]\n" + + "b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]\n" + + "c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]\n" + + "d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]\n" + + "e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]\n" + + "f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]\n" + + "g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]\n" + + "h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]\n" + + "i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]\n", + "yaml: document contains excessive aliasing", + }, } func (s *S) TestUnmarshalErrors(c *C) {