Skip to content

Data race #852

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

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions