From fe45f2779f4a4eac95eac466aa2feb0860dc41b0 Mon Sep 17 00:00:00 2001 From: SAY-5 Date: Sat, 2 May 2026 20:38:42 -0700 Subject: [PATCH] fix(transformers): serialize UTCTimestampTransformer to avoid rng race greenmask's Timestamp holds a *rand.Rand that is not concurrency-safe, but pgstream shares one transformer across snapshot worker goroutines. Concurrent calls corrupted the shared rng and panicked deep in math/rand.(*rngSource).Uint64. Guard the Transform call with a per-instance mutex. Signed-off-by: SAY-5 --- .../greenmask/greenmask_timestamp_transformer.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/transformers/greenmask/greenmask_timestamp_transformer.go b/pkg/transformers/greenmask/greenmask_timestamp_transformer.go index 2188ef0d..41a12f97 100644 --- a/pkg/transformers/greenmask/greenmask_timestamp_transformer.go +++ b/pkg/transformers/greenmask/greenmask_timestamp_transformer.go @@ -6,6 +6,7 @@ import ( "context" "errors" "fmt" + "sync" "time" greenmasktransformers "github.com/eminano/greenmask/pkg/generators/transformers" @@ -13,6 +14,7 @@ import ( ) type UTCTimestampTransformer struct { + mu sync.Mutex transformer *greenmasktransformers.Timestamp } @@ -117,6 +119,12 @@ func (t *UTCTimestampTransformer) Transform(_ context.Context, value transformer default: return nil, transformers.ErrUnsupportedValueType } + // greenmask's Timestamp transformer holds a *rand.Rand that is not safe + // for concurrent use, but pgstream shares one transformer across snapshot + // worker goroutines. Serialize the call so concurrent writers don't + // corrupt the shared rng (issue #789). + t.mu.Lock() + defer t.mu.Unlock() return t.transformer.Transform(nil, toTransform) }