From 38b955a4a10cc5770497251386dbe393a69df4ab Mon Sep 17 00:00:00 2001 From: Nick Sieger Date: Thu, 9 Jun 2022 15:44:29 -0500 Subject: [PATCH] project: ensure withServices doesn't blow stack on cycles Change `done` map to `seen` and record service was seen before traversing dependencies. Fixes docker/compose#9526. Signed-off-by: Nick Sieger --- types/project.go | 8 ++++---- types/project_test.go | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/types/project.go b/types/project.go index 1c7a7e40..19e5de0e 100644 --- a/types/project.go +++ b/types/project.go @@ -142,18 +142,19 @@ func (p Project) WithServices(names []string, fn ServiceFunc) error { return p.withServices(names, fn, map[string]bool{}) } -func (p Project) withServices(names []string, fn ServiceFunc, done map[string]bool) error { +func (p Project) withServices(names []string, fn ServiceFunc, seen map[string]bool) error { services, err := p.GetServices(names...) if err != nil { return err } for _, service := range services { - if done[service.Name] { + if seen[service.Name] { continue } + seen[service.Name] = true dependencies := service.GetDependencies() if len(dependencies) > 0 { - err := p.withServices(dependencies, fn, done) + err := p.withServices(dependencies, fn, seen) if err != nil { return err } @@ -161,7 +162,6 @@ func (p Project) withServices(names []string, fn ServiceFunc, done map[string]bo if err := fn(service); err != nil { return err } - done[service.Name] = true } return nil } diff --git a/types/project_test.go b/types/project_test.go index 203c7a03..b46ffb91 100644 --- a/types/project_test.go +++ b/types/project_test.go @@ -83,6 +83,13 @@ func Test_ForServices(t *testing.T) { assert.Equal(t, p.DisabledServices[0].Name, "service_3") } +func Test_ForServicesCycle(t *testing.T) { + p := makeProject() + p.Services[0].Links = []string{"service_2"} + err := p.ForServices([]string{"service_2"}) + assert.NilError(t, err) +} + func makeProject() Project { return Project{ Services: append(Services{},