Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Commit

Permalink
cmd/cue/cmd: prevent infinite loops while building dependency graph
Browse files Browse the repository at this point in the history
The existing implementatin resulted in an infinite loop in two cases:

1. In the v.Equals(after) call when the 'after' dependencies were cyclic
2. In the task.Walk function when task fields cyclically referenced
other tasks

This commit solves both cases by
- stepping out of the Walk lambda when it had already been evaluated
with the given parameter; and
- removing the special case for 'after' dependencies as it is no longer
necessary.

Relevent tests are included.

Updates #245

Change-Id: I914ff9aad96eb43ae89964000dea60ccd44c38a2
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4910
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
  • Loading branch information
grantzvolsky authored and mpvl committed Feb 17, 2020
1 parent 0846b93 commit bfdc423
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
14 changes: 12 additions & 2 deletions cmd/cue/cmd/custom.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,23 @@ func executeTasks(cmd *Command, typ, command string, inst *cue.Instance) (err er
exitIfErr(cmd, inst, err, true)
}

visited := make(map[string]bool)
task.Walk(func(v cue.Value) bool {
if v == task {
return true
}
if after.Err() == nil && v.Equals(after) {
return false

// Prevent inifinite walks
_, vPath := v.Reference()
if vPath != nil {
vPath := string(keyForReference(vPath...))
_, isVisited := visited[vPath]
if isVisited {
return false
}
visited[vPath] = true
}

for _, r := range appendReferences(nil, cr.root, v) {
if dep := cr.findTask(r); dep != nil && t != dep {
// TODO(string): consider adding dependencies
Expand Down
33 changes: 33 additions & 0 deletions cmd/cue/cmd/testdata/script/cmd_dep_cycle.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
! cue cmd cycle
cmp stderr expect-stderr
! cue cmd aftercycle
cmp stderr expect-stderr
cue cmd interlockedTasks
cmp stdout interlocked-stdout

-- expect-stderr --
cyclic dependency in tasks
-- interlocked-stdout --
v
v
-- after_tool.cue --
package home

import (
"tool/cli"
)

command: interlockedTasks: {
t1: cli.Print & { text: ref.value, ref: t2, value: "v" }
t2: cli.Print & { text: ref.value, ref: t1, value: "v" }
}

command: aftercycle: {
t1: cli.Print & { $after: t2, text: "t1" }
t2: cli.Print & { $after: t1, text: "t2" }
}

command: cycle: {
t1: cli.Print & { text: t2.text }
t2: cli.Print & { text: t1.text }
}

0 comments on commit bfdc423

Please sign in to comment.