fix race condition in string generator helper (#19875)

* fix race condition in string generator helper

* add changelog
This commit is contained in:
John-Michael Faircloth 2023-03-31 10:19:45 -05:00 committed by GitHub
parent de56c728a1
commit 72f5ed8fe1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 12 additions and 2 deletions

3
changelog/19875.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
helper/random: Fix race condition in string generator helper
```

View File

@ -10,6 +10,7 @@ import (
"io" "io"
"math" "math"
"sort" "sort"
"sync"
"time" "time"
"unicode" "unicode"
@ -79,7 +80,8 @@ type StringGenerator struct {
Rules serializableRules `mapstructure:"-" json:"rule"` // This is "rule" in JSON so it matches the HCL property type Rules serializableRules `mapstructure:"-" json:"rule"` // This is "rule" in JSON so it matches the HCL property type
// CharsetRule to choose runes from. This is computed from the rules, not directly configurable // CharsetRule to choose runes from. This is computed from the rules, not directly configurable
charset runes charset runes
charsetLock sync.RWMutex
} }
// Generate a random string from the charset and adhering to the provided rules. // Generate a random string from the charset and adhering to the provided rules.
@ -119,7 +121,10 @@ func (g *StringGenerator) generate(rng io.Reader) (str string, err error) {
// If performance improvements need to be made, this can be changed to read a batch of // If performance improvements need to be made, this can be changed to read a batch of
// potential strings at once rather than one at a time. This will significantly // potential strings at once rather than one at a time. This will significantly
// improve performance, but at the cost of added complexity. // improve performance, but at the cost of added complexity.
candidate, err := randomRunes(rng, g.charset, g.Length) g.charsetLock.RLock()
charset := g.charset
g.charsetLock.RUnlock()
candidate, err := randomRunes(rng, charset, g.Length)
if err != nil { if err != nil {
return "", fmt.Errorf("unable to generate random characters: %w", err) return "", fmt.Errorf("unable to generate random characters: %w", err)
} }
@ -232,6 +237,8 @@ func (g *StringGenerator) validateConfig() (err error) {
merr = multierror.Append(merr, fmt.Errorf("specified rules require at least %d characters but %d is specified", minLen, g.Length)) merr = multierror.Append(merr, fmt.Errorf("specified rules require at least %d characters but %d is specified", minLen, g.Length))
} }
g.charsetLock.Lock()
defer g.charsetLock.Unlock()
// Ensure we have a charset & all characters are printable // Ensure we have a charset & all characters are printable
if len(g.charset) == 0 { if len(g.charset) == 0 {
// Yes this is mutating the generator but this is done so we don't have to compute this on every generation // Yes this is mutating the generator but this is done so we don't have to compute this on every generation