hashicorp / go-getter

Package for downloading things from a string URL using a variety of protocols.
Mozilla Public License 2.0
1.62k stars 227 forks source link

fix(getter): race condition when SetClient is called #466

Open srevinsaju opened 8 months ago

srevinsaju commented 8 months ago

This is a non-breaking change. This fixes an issue when Clients are created and called concurrently. Clients called SetClient on each of the Getters. When no getters were provided, it modified the clients of the default getters defined in the Getters map. Since the map was mutated from multiple goroutines, it creates a race condition 'concurrent map writes'. The issue is mitigated by creating a new copy of Getters using DefaultGetters() function for every new client created. SetClient now modifies its own copy of the Getter, not the default Getters.

To reproduce the issue:

mkdir hello
touch hello/world
// main.go
package main

import "github.com/hashicorp/go-getter"
import "context"
import "os"
import "sync"
import "path/filepath"

func main() {
    var wg sync.WaitGroup
    cwd, err := os.Getwd()
    if err != nil {
        panic(err)
    }
    keys := []string{"a", "b", "c"}

    for _, key := range keys {
        wg.Add(1)
        go func(key string) {
            get := &getter.Client{
                Ctx: context.Background(),
                Src: "./hello",
                Dst: filepath.Join("dest", key),
                Pwd: cwd,
                Dir: true,
            }
      err := get.Get()
            if err != nil {
                panic(err)
            }
            wg.Done()
        }(key)
    }
    wg.Wait()
}
go run -race .
hashicorp-cla commented 8 months ago

CLA assistant check
All committers have signed the CLA.