Skip to content

Data race #852

@eaudetcobello

Description

@eaudetcobello

There may be a concurrency issue where the goroutine writes to newProject.Services while the for loop reads it:

  eg.Go(func() error {        // line 799: collector goroutine starts                                                                                                                                                                                       
      s := Services{}                                                                                                                                                                                                                                       
      for expect > 0 {        // line 801: if expect==0, skip loop entirely                                                                                                                                                                                 
          // ...                                                                                                                                                                                                                                            
          s[r.name] = r.service
          expect--
      }
      newProject.Services = s  // line 811: WRITE to newProject.Services
      return nil
  })
  for n, s := range newProject.Services {  // line 814: READ newProject.Services
      // ... spawn workers
  }

Here is the -race output specifying a read at project.go:814 and a write at project.go:811:

WARNING: DATA RACE                                                                                                                                                                                                                                    
  Write at 0x00c0008102a0 by goroutine 34:                                                                                                                                                                                                              
    github.com/compose-spec/compose-go/v2/types.(*Project).WithServicesTransform.func1()                                                                                                                                                                    
        /Users/user/go/pkg/mod/github.com/compose-spec/compose-go/v2@v2.9.0/types/project.go:811 +0x230                                                                                                                                                 
    golang.org/x/sync/errgroup.(*Group).Go.func1()                                                                                                                                                                                                          
        /Users/user/go/pkg/mod/golang.org/x/sync@v0.19.0/errgroup/errgroup.go:93 +0x70                                                                                                                                                                  
                                                                                                                                                                                                                                                        
  Previous read at 0x00c0008102a0 by goroutine 33:                                                                                                                                                                                                      
    github.com/compose-spec/compose-go/v2/types.(*Project).WithServicesTransform()                                                                                                                                                                      
        /Users/user/go/pkg/mod/github.com/compose-spec/compose-go/v2@v2.9.0/types/project.go:814 +0x2d4                                                                                                                                                 
    github.com/docker/compose/v2/pkg/compose.(*composeService).getProjectWithResources()                                                                                                                                                                
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:386 +0xe4                                                                                                                                                       
    github.com/docker/compose/v2/pkg/compose.(*composeService).down()                                                                                                                                                                                   
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:61 +0x128                                                                                                                                                       
    github.com/docker/compose/v2/pkg/compose.(*composeService).down()                                                                                                                                                                                   
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:54 +0xec                                                                                                                                                        
    github.com/docker/compose/v2/pkg/compose.(*composeService).Down.func1()                                                                                                                                                                             
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:42 +0xa4                                                                                                                                                        
    github.com/docker/compose/v2/pkg/progress.Run.func1()                                                                                                                                                                                               
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/progress/writer.go:63 +0x44                                                                                                                                                     
    github.com/docker/compose/v2/pkg/progress.RunWithStatus.func2()                                                                                                                                                                                     
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/progress/writer.go:110 +0xa4                                                                                                                                                    
    golang.org/x/sync/errgroup.(*Group).Go.func1()                                                                                                                                                                                                      
        /Users/user/go/pkg/mod/golang.org/x/sync@v0.19.0/errgroup/errgroup.go:93 +0x70                                                                                                                                                                  
                                                                                                                                                                                                                                                        
  Goroutine 34 (running) created at:                                                                                                                                                                                                                    
    golang.org/x/sync/errgroup.(*Group).Go()                                                                                                                                                                                                            
        /Users/user/go/pkg/mod/golang.org/x/sync@v0.19.0/errgroup/errgroup.go:78 +0x104                                                                                                                                                                 
    github.com/compose-spec/compose-go/v2/types.(*Project).WithServicesTransform()                                                                                                                                                                      
        /Users/user/go/pkg/mod/github.com/compose-spec/compose-go/v2@v2.9.0/types/project.go:799 +0x2c4                                                                                                                                                 
    github.com/docker/compose/v2/pkg/compose.(*composeService).getProjectWithResources()                                                                                                                                                                
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:386 +0xe4                                                                                                                                                       
    github.com/docker/compose/v2/pkg/compose.(*composeService).down()                                                                                                                                                                                   
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:61 +0x128                                                                                                                                                       
    github.com/docker/compose/v2/pkg/compose.(*composeService).down()                                                                                                                                                                                   
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:54 +0xec                                                                                                                                                        
    github.com/docker/compose/v2/pkg/compose.(*composeService).Down.func1()                                                                                                                                                                             
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:42 +0xa4                                                                                                                                                        
    github.com/docker/compose/v2/pkg/progress.Run.func1()                                                                                                                                                                                               
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/progress/writer.go:63 +0x44                                                                                                                                                     
    github.com/docker/compose/v2/pkg/progress.RunWithStatus.func2()                                                                                                                                                                                     
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/progress/writer.go:110 +0xa4                                                                                                                                                    
    golang.org/x/sync/errgroup.(*Group).Go.func1()                                                                                                                                                                                                      
        /Users/user/go/pkg/mod/golang.org/x/sync@v0.19.0/errgroup/errgroup.go:93 +0x70                                                                                                                                                                  
                                                                                                                                                                                                                                                        
  Goroutine 33 (running) created at:                                                                                                                                                                                                                    
    golang.org/x/sync/errgroup.(*Group).Go()                                                                                                                                                                                                            
        /Users/user/go/pkg/mod/golang.org/x/sync@v0.19.0/errgroup/errgroup.go:78 +0x104                                                                                                                                                                 
    github.com/docker/compose/v2/pkg/progress.RunWithStatus()                                                                                                                                                                                           
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/progress/writer.go:108 +0x2f8                                                                                                                                                   
    github.com/docker/compose/v2/pkg/progress.Run()                                                                                                                                                                                                     
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/progress/writer.go:62 +0xa4                                                                                                                                                     
    github.com/docker/compose/v2/pkg/compose.(*composeService).Down()                                                                                                                                                                                   
        /Users/user/go/pkg/mod/github.com/docker/compose/v2@v2.40.2/pkg/compose/down.go:41 +0x150                                                                                                                                                       
    github.com/testcontainers/testcontainers-go/modules/compose.(*DockerCompose).Down()                                                                                                                                                                 
        /Users/user/go/pkg/mod/github.com/testcontainers/testcontainers-go/modules/compose@v0.40.0/compose_api.go:271 +0x24c                                                                                                                            
    bitbucket.org/contoso/my-code-repo/e2e/infra.New()                                                                                                                                                                                                 
        /Users/user/Developer/contoso.com/my-code-repo/e2e/infra/testcontainers.go:111 +0x4c0                                                                                                                                                          
    github.com/testcontainers/testcontainers-go/modules/compose.NewDockerCompose()                                                                                                                                                                      
        /Users/user/go/pkg/mod/github.com/testcontainers/testcontainers-go/modules/compose@v0.40.0/compose.go:127 +0x188                                                                                                                                
    bitbucket.org/contoso/my-code-repo/e2e/infra.New()                                                                                                                                                                                                 
        /Users/user/Developer/contoso.com/my-code-repo/e2e/infra/testcontainers.go:83 +0x140                                                                                                                                                           
    bitbucket.org/contoso/my-code-repo/e2e.TestMain()                                                                                                                                                                                                  
        /Users/user/Developer/contoso.com/my-code-repo/e2e/main_test.go:25 +0xb4                                                                                                                                                                       
    main.main()                                                                                                                                                                                                                                         
        _testmain.go:82 +0x104                                                                                                                                                                                                                          
  ==================                                       

This patch fixes the issue locally:

--- a/vendor/github.com/compose-spec/compose-go/v2/types/project.go
+++ b/vendor/github.com/compose-spec/compose-go/v2/types/project.go
@@ -795,6 +795,10 @@
 	resultCh := make(chan result, expect)
 	newProject := p.deepCopy()

+	// Capture services before spawning the collector goroutine to avoid
+	// a data race between the collector writing newProject.Services and
+	// the range reading it. See https://github.com/compose-spec/compose-go/issues/852
+	services := newProject.Services
 	eg, ctx := errgroup.WithContext(context.Background())
 	eg.Go(func() error {
 		s := Services{}
@@ -811,7 +815,7 @@
 		newProject.Services = s
 		return nil
 	})
-	for n, s := range newProject.Services {
+	for n, s := range services {
 		name := n
 		service := s
 		eg.Go(func() error {

Versions: compose-spec/compose-go/v2 v2.9.0, docker/compose/v2 v2.40.2, testcontainers-go v0.40.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions