Skip to content

Commit ca2a14e

Browse files
bucketscache: add RWMutex (#2316)
Buckets map was unprotected by a mutex. Usage of the module in event logics potentially caused a race condition in map read write. Fix #2313. Further, add tests for the package.
1 parent 534b6a4 commit ca2a14e

File tree

2 files changed

+65
-8
lines changed

2 files changed

+65
-8
lines changed

pkg/bucketscache/bucketscache.go

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,39 @@
11
package bucketscache
22

3+
import (
4+
"fmt"
5+
"sync"
6+
)
7+
38
type BucketsCache struct {
4-
buckets map[uint32][]uint32
5-
bucketLimit int
6-
Null uint32
9+
buckets map[uint32][]uint32
10+
bucketLimit int
11+
bucketsMutex *sync.RWMutex
712
}
813

914
func (c *BucketsCache) Init(bucketLimit int) {
1015
c.bucketLimit = bucketLimit
1116
c.buckets = make(map[uint32][]uint32)
12-
c.Null = 0
17+
c.bucketsMutex = new(sync.RWMutex)
1318
}
1419

1520
func (c *BucketsCache) GetBucket(key uint32) []uint32 {
21+
c.bucketsMutex.RLock()
22+
defer c.bucketsMutex.RUnlock()
1623
return c.buckets[key]
1724
}
1825

19-
func (c *BucketsCache) GetBucketItem(key uint32, index int) uint32 {
26+
func (c *BucketsCache) GetBucketItem(key uint32, index int) (uint32, error) {
27+
c.bucketsMutex.RLock()
28+
defer c.bucketsMutex.RUnlock()
2029
b, exists := c.buckets[key]
2130
if !exists {
22-
return c.Null
31+
return 0, NoSuchItem(key, index)
2332
}
2433
if index >= len(b) {
25-
return c.Null
34+
return 0, NoSuchItem(key, index)
2635
}
27-
return b[index]
36+
return b[index], nil
2837
}
2938

3039
func (c *BucketsCache) AddBucketItem(key uint32, value uint32) {
@@ -36,10 +45,14 @@ func (c *BucketsCache) ForceAddBucketItem(key uint32, value uint32) {
3645
}
3746

3847
func (c *BucketsCache) addBucketItem(key uint32, value uint32, force bool) {
48+
c.bucketsMutex.RLock()
3949
b, exists := c.buckets[key]
50+
c.bucketsMutex.RUnlock()
4051
if !exists {
52+
c.bucketsMutex.Lock()
4153
c.buckets[key] = make([]uint32, 0, c.bucketLimit)
4254
b = c.buckets[key]
55+
c.bucketsMutex.Unlock()
4356
}
4457
if len(b) >= c.bucketLimit {
4558
if force {
@@ -48,6 +61,12 @@ func (c *BucketsCache) addBucketItem(key uint32, value uint32, force bool) {
4861
return
4962
}
5063
} else {
64+
c.bucketsMutex.Lock()
5165
c.buckets[key] = append(b, value)
66+
c.bucketsMutex.Unlock()
5267
}
5368
}
69+
70+
func NoSuchItem(key uint32, index int) error {
71+
return fmt.Errorf("no such item in cache at key: %d, index: %d", key, index)
72+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package bucketscache_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/aquasecurity/tracee/pkg/bucketscache"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestBucketsCache(t *testing.T) {
12+
var cache bucketscache.BucketsCache
13+
cache.Init(5)
14+
cache.AddBucketItem(1, 32)
15+
cache.AddBucketItem(1, 32)
16+
cache.AddBucketItem(1, 32)
17+
cache.AddBucketItem(1, 32)
18+
cache.AddBucketItem(1, 32)
19+
cache.AddBucketItem(1, 33) // should not do anything
20+
bucket := cache.GetBucket(1)
21+
assert.ElementsMatch(t, bucket, []uint32{32, 32, 32, 32, 32})
22+
cache.ForceAddBucketItem(1, 33) // force 33 to index 0
23+
bucket = cache.GetBucket(1)
24+
assert.ElementsMatch(t, bucket, []uint32{33, 32, 32, 32, 32})
25+
26+
// get non existing bucket
27+
bucket = cache.GetBucket(2)
28+
assert.Empty(t, bucket)
29+
30+
// get existing bucket item
31+
item, err := cache.GetBucketItem(1, 0)
32+
require.NoError(t, err)
33+
assert.Equal(t, item, uint32(33))
34+
35+
// get non existing bucket item
36+
_, err = cache.GetBucketItem(2, 0)
37+
assert.Equal(t, err.Error(), bucketscache.NoSuchItem(2, 0).Error())
38+
}

0 commit comments

Comments
 (0)