From facb2b13e8195a69a68307c24cd8ed6610446a18 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Sun, 12 Dec 2021 09:43:42 -0500 Subject: [PATCH] Decoder: prevent modification of inline tables (#702) Fixes #701 --- internal/tracker/seen.go | 19 +++++++++++++++++++ unmarshaler_test.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/internal/tracker/seen.go b/internal/tracker/seen.go index 4c2153e..167790d 100644 --- a/internal/tracker/seen.go +++ b/internal/tracker/seen.go @@ -145,6 +145,11 @@ func (s *SeenTracker) checkTable(node *ast.Node) error { if idx < 0 { idx = s.create(parentIdx, k, tableKind, false) + } else { + entry := s.entries[idx] + if entry.kind == valueKind { + return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind) + } } parentIdx = idx } @@ -186,7 +191,13 @@ func (s *SeenTracker) checkArrayTable(node *ast.Node) error { if idx < 0 { idx = s.create(parentIdx, k, tableKind, false) + } else { + entry := s.entries[idx] + if entry.kind == valueKind { + return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind) + } } + parentIdx = idx } @@ -281,6 +292,14 @@ func (s *SeenTracker) checkInlineTable(parentIdx int, node *ast.Node) error { return err } } + + // As inline tables are self-contained, the tracker does not + // need to retain the details of what they contain. The + // keyValue element that creates the inline table is kept to + // mark the presence of the inline table and prevent + // redefinition of its keys: check* functions cannot walk into + // a value. + s.clear(parentIdx) return nil } diff --git a/unmarshaler_test.go b/unmarshaler_test.go index 39915e7..5339b6a 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -2270,7 +2270,34 @@ Program = "hugo" require.Equal(t, expected, p) } -//nolint:funlen +func TestIssue701(t *testing.T) { + // Expected behavior: + // Return an error since a cannot be modified. From the TOML spec: + // + // > Inline tables are fully self-contained and define all + // keys and sub-tables within them. Keys and sub-tables cannot + // be added outside the braces. + + docs := []string{ + ` +a={} +[a.b] +z=0 +`, + ` +a={} +[[a.b]] +z=0 +`, + } + + for _, doc := range docs { + var v interface{} + err := toml.Unmarshal([]byte(doc), &v) + assert.Error(t, err) + } +} + func TestUnmarshalDecodeErrors(t *testing.T) { examples := []struct { desc string