mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
fix: resolve data race in token.RNG global
Wrap *rand.Rand in a mutex-protected SafeRand type to make the global RNG safe for concurrent use across goroutines. The previous bare *rand.Rand caused data races detected by go test -race.
This commit is contained in:
@@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Fixed save operation ordering - now saves data before session cleanup instead of after
|
- Fixed save operation ordering - now saves data before session cleanup instead of after
|
||||||
- Fixed stale transmog/armor appearance shown to other players - user binary cache now invalidated when plate data is saved
|
- Fixed stale transmog/armor appearance shown to other players - user binary cache now invalidated when plate data is saved
|
||||||
- Fixed server crash when Discord relay receives messages with unsupported Shift-JIS characters (emoji, Lenny faces, cuneiform, etc.)
|
- Fixed server crash when Discord relay receives messages with unsupported Shift-JIS characters (emoji, Lenny faces, cuneiform, etc.)
|
||||||
|
- Fixed data race in token.RNG global used concurrently across goroutines
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
|
|||||||
@@ -539,7 +539,7 @@ func TestDiffItemStacks_GeneratesNewWarehouseID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset RNG for consistent test
|
// Reset RNG for consistent test
|
||||||
token.RNG = token.NewRNG()
|
token.RNG = token.NewSafeRand()
|
||||||
|
|
||||||
result := DiffItemStacks(old, update)
|
result := DiffItemStacks(old, update)
|
||||||
if len(result) != 1 {
|
if len(result) != 1 {
|
||||||
|
|||||||
@@ -2,10 +2,37 @@ package token
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var RNG = NewRNG()
|
// SafeRand is a concurrency-safe wrapper around *rand.Rand.
|
||||||
|
type SafeRand struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
rng *rand.Rand
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSafeRand() *SafeRand {
|
||||||
|
return &SafeRand{
|
||||||
|
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sr *SafeRand) Intn(n int) int {
|
||||||
|
sr.mu.Lock()
|
||||||
|
v := sr.rng.Intn(n)
|
||||||
|
sr.mu.Unlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sr *SafeRand) Uint32() uint32 {
|
||||||
|
sr.mu.Lock()
|
||||||
|
v := sr.rng.Uint32()
|
||||||
|
sr.mu.Unlock()
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
var RNG = NewSafeRand()
|
||||||
|
|
||||||
// Generate returns an alphanumeric token of specified length
|
// Generate returns an alphanumeric token of specified length
|
||||||
func Generate(length int) string {
|
func Generate(length int) string {
|
||||||
@@ -16,8 +43,3 @@ func Generate(length int) string {
|
|||||||
}
|
}
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRNG returns a new NewRNG generator
|
|
||||||
func NewRNG() *rand.Rand {
|
|
||||||
return rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package token
|
package token
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -134,10 +133,10 @@ func TestGenerate_Distribution(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewRNG(t *testing.T) {
|
func TestNewSafeRand(t *testing.T) {
|
||||||
rng := NewRNG()
|
rng := NewSafeRand()
|
||||||
if rng == nil {
|
if rng == nil {
|
||||||
t.Fatal("NewRNG() returned nil")
|
t.Fatal("NewSafeRand() returned nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that it produces different values on subsequent calls
|
// Test that it produces different values on subsequent calls
|
||||||
@@ -154,7 +153,7 @@ func TestNewRNG(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if same {
|
if same {
|
||||||
t.Error("NewRNG() produced same value 12 times in a row")
|
t.Error("NewSafeRand() produced same value 12 times in a row")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -237,11 +236,11 @@ func TestGenerate_OnlyAlphanumeric(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewRNG_DifferentSeeds(t *testing.T) {
|
func TestNewSafeRand_DifferentSeeds(t *testing.T) {
|
||||||
// Create two RNGs at different times and verify they produce different sequences
|
// Create two RNGs at different times and verify they produce different sequences
|
||||||
rng1 := NewRNG()
|
rng1 := NewSafeRand()
|
||||||
time.Sleep(1 * time.Millisecond) // Ensure different seed
|
time.Sleep(1 * time.Millisecond) // Ensure different seed
|
||||||
rng2 := NewRNG()
|
rng2 := NewSafeRand()
|
||||||
|
|
||||||
val1 := rng1.Intn(1000000)
|
val1 := rng1.Intn(1000000)
|
||||||
val2 := rng2.Intn(1000000)
|
val2 := rng2.Intn(1000000)
|
||||||
@@ -278,15 +277,15 @@ func BenchmarkGenerate_Long(b *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkNewRNG(b *testing.B) {
|
func BenchmarkNewSafeRand(b *testing.B) {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = NewRNG()
|
_ = NewSafeRand()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRNG_Intn(b *testing.B) {
|
func BenchmarkRNG_Intn(b *testing.B) {
|
||||||
rng := NewRNG()
|
rng := NewSafeRand()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = rng.Intn(62)
|
_ = rng.Intn(62)
|
||||||
@@ -294,7 +293,7 @@ func BenchmarkRNG_Intn(b *testing.B) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRNG_Uint32(b *testing.B) {
|
func BenchmarkRNG_Uint32(b *testing.B) {
|
||||||
rng := NewRNG()
|
rng := NewSafeRand()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = rng.Uint32()
|
_ = rng.Uint32()
|
||||||
@@ -334,7 +333,7 @@ func TestGenerate_ConsistentCharacterSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRNG_Type(t *testing.T) {
|
func TestRNG_Type(t *testing.T) {
|
||||||
// Verify RNG is of type *rand.Rand
|
// Verify RNG is of type *SafeRand
|
||||||
var _ *rand.Rand = RNG
|
var _ *SafeRand = RNG
|
||||||
var _ *rand.Rand = NewRNG()
|
var _ *SafeRand = NewSafeRand()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user