From 72f5ed8fe1fc7e775bbf56bcf0f665d7f12e993e Mon Sep 17 00:00:00 2001 From: John-Michael Faircloth Date: Fri, 31 Mar 2023 10:19:45 -0500 Subject: [PATCH] fix race condition in string generator helper (#19875) * fix race condition in string generator helper * add changelog --- changelog/19875.txt | 3 +++ helper/random/string_generator.go | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 changelog/19875.txt diff --git a/changelog/19875.txt b/changelog/19875.txt new file mode 100644 index 000000000..1167e39b3 --- /dev/null +++ b/changelog/19875.txt @@ -0,0 +1,3 @@ +```release-note:bug +helper/random: Fix race condition in string generator helper +``` diff --git a/helper/random/string_generator.go b/helper/random/string_generator.go index c51d29a55..e7c087aa3 100644 --- a/helper/random/string_generator.go +++ b/helper/random/string_generator.go @@ -10,6 +10,7 @@ import ( "io" "math" "sort" + "sync" "time" "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 // 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. @@ -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 // potential strings at once rather than one at a time. This will significantly // 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 { 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)) } + g.charsetLock.Lock() + defer g.charsetLock.Unlock() // Ensure we have a charset & all characters are printable 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