Skip to content

Commit 3dfb833

Browse files
authored
parser: prevent self-reference within templates (#4)
Signed-off-by: Abiola Ibrahim <git@abiosoft.com>
1 parent 57634a6 commit 3dfb833

2 files changed

Lines changed: 23 additions & 11 deletions

File tree

mold_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ func TestNew_ViewParseError(t *testing.T) {
8787
}
8888
}
8989

90+
func TestNew_CyclicReferenceError(t *testing.T) {
91+
testFS := createTestFS(testFile{"parse.html", `{{partial "parse.html"}}`})
92+
93+
if _, err := New(testFS); err == nil {
94+
t.Errorf("New() expected error, got nil %v", err)
95+
}
96+
}
97+
9098
func TestNew_Ext(t *testing.T) {
9199
testFS := createTestFS(
92100
testFile{"layout.mine", "{{render}}"},

tree.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
// processTree traverses the node tree and swaps render and partial declarations with equivalent template calls.
1111
// It returns all referenced templates encountered during the traversal.
1212
func processTree(t *template.Template, raw string) ([]templateName, error) {
13-
ts, err := processNode(nil, 0, t.Tree.Root)
13+
ts, err := processNode(t.Tree, nil, 0, t.Tree.Root)
1414
if err != nil {
1515
if err, ok := err.(posErr); ok {
1616
line, col := pos(raw, err.pos)
@@ -21,7 +21,7 @@ func processTree(t *template.Template, raw string) ([]templateName, error) {
2121
return ts, nil
2222
}
2323

24-
func processNode(parent *parse.ListNode, index int, node parse.Node) (ts []templateName, err error) {
24+
func processNode(tree *parse.Tree, parent *parse.ListNode, index int, node parse.Node) (ts []templateName, err error) {
2525
// appendResult appends the specified templates to the list of template names when there are no errors
2626
appendResult := func(t []templateName, err1 error) {
2727
if err1 != nil {
@@ -35,7 +35,7 @@ func processNode(parent *parse.ListNode, index int, node parse.Node) (ts []templ
3535
if a, ok := node.(*parse.ActionNode); ok {
3636
if len(a.Pipe.Cmds) > 0 {
3737
funcName, tname, _ := getActionArgs(a.Pipe.Cmds[0])
38-
if err := processActionNode(parent, index, node, funcName); err != nil {
38+
if err := processActionNode(tree, parent, index, node, funcName); err != nil {
3939
return ts, err
4040
}
4141
if funcName == partialFunc.String() && tname != "" {
@@ -47,27 +47,27 @@ func processNode(parent *parse.ListNode, index int, node parse.Node) (ts []templ
4747
}
4848

4949
if w, ok := node.(*parse.WithNode); ok && w != nil {
50-
appendResult(processNode(parent, index, w.List))
51-
appendResult(processNode(parent, index, w.ElseList))
50+
appendResult(processNode(tree, parent, index, w.List))
51+
appendResult(processNode(tree, parent, index, w.ElseList))
5252
}
5353
if l, ok := node.(*parse.ListNode); ok && l != nil {
5454
for i, n := range l.Nodes {
55-
appendResult(processNode(l, i, n))
55+
appendResult(processNode(tree, l, i, n))
5656
}
5757
}
5858
if i, ok := node.(*parse.IfNode); ok && i != nil {
59-
appendResult(processNode(parent, index, i.List))
60-
appendResult(processNode(parent, index, i.ElseList))
59+
appendResult(processNode(tree, parent, index, i.List))
60+
appendResult(processNode(tree, parent, index, i.ElseList))
6161
}
6262
if r, ok := node.(*parse.RangeNode); ok && r != nil {
63-
appendResult(processNode(parent, index, r.List))
64-
appendResult(processNode(parent, index, r.ElseList))
63+
appendResult(processNode(tree, parent, index, r.List))
64+
appendResult(processNode(tree, parent, index, r.ElseList))
6565
}
6666

6767
return ts, err
6868
}
6969

70-
func processActionNode(parent *parse.ListNode, index int, node parse.Node, funcName string) error {
70+
func processActionNode(tree *parse.Tree, parent *parse.ListNode, index int, node parse.Node, funcName string) error {
7171
if parent == nil {
7272
// this should never happen
7373
return errors.New("processActionNode error: parent node is nil")
@@ -77,6 +77,10 @@ func processActionNode(parent *parse.ListNode, index int, node parse.Node, funcN
7777
cmd := actionNode.Pipe.Cmds[0]
7878
_, name, field := getActionArgs(cmd)
7979

80+
if name == tree.ParseName {
81+
return posErr{pos: int(actionNode.Pos), message: fmt.Sprintf(`cyclic reference for '%s'`, name)}
82+
}
83+
8084
var arg parse.Node = &parse.DotNode{}
8185

8286
// only handle if the function name is render or partial

0 commit comments

Comments
 (0)