mirror of
https://github.com/gofiber/storage.git
synced 2025-12-19 00:38:24 +08:00
Fix: Prevent memory corruption from pooled buffers in memory storage
Problem: The memory storage uses string keys and byte slice values directly in a Go map without copying them. When these strings/slices are backed by pooled buffers (from sync.Pool used by Fiber for performance), the map keys and values can become corrupted when those buffers are reused. Root Cause: 1. Fiber v3 uses sync.Pool extensively for byte buffer reuse 2. Strings created from pooled buffers point to the underlying pooled memory 3. When used as Go map keys without copying, these strings share the pooled buffer 4. When the buffer is returned to the pool and reused, the map key gets corrupted 5. This causes intermittent failures where sessions/CSRF tokens cannot be found Solution: Copy both the key (string) and value ([]byte) before storing in the map. Since this package doesn't have access to gofiber/utils, we use manual copying: - Key: string([]byte(key)) - creates a new string with a new backing array - Value: make new slice and copy bytes Testing: - Before fix: ~8% pass rate with ginkgo --repeat=100 - After fix: 100% pass rate with ginkgo --repeat=200 - No corrupted keys found in storage after fix Impact: - Performance: Minimal - one string copy and one byte slice copy per Set - Safety: Prevents entire class of memory corruption bugs - Consistency: Aligns with the fix applied to gofiber/fiber internal storage
This commit is contained in:
@@ -64,13 +64,19 @@ func (s *Storage) Set(key string, val []byte, exp time.Duration) error {
|
||||
}
|
||||
|
||||
var expire uint32
|
||||
// Copy both key and value to avoid unsafe reuse from sync.Pool
|
||||
// When Fiber uses pooled buffers, the underlying memory can be reused
|
||||
keyCopy := string([]byte(key))
|
||||
valCopy := make([]byte, len(val))
|
||||
copy(valCopy, val)
|
||||
|
||||
if exp != 0 {
|
||||
expire = uint32(exp.Seconds()) + atomic.LoadUint32(&internal.Timestamp)
|
||||
}
|
||||
|
||||
e := entry{val, expire}
|
||||
e := entry{valCopy, expire}
|
||||
s.mux.Lock()
|
||||
s.db[key] = e
|
||||
s.db[keyCopy] = e
|
||||
s.mux.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user