Skip to content

Commit f83447b

Browse files
tonistiigicrazy-max
authored andcommitted
solver: fix possible concurrent map access on cache export
Signed-off-by: Tonis Tiigi <[email protected]> (cherry picked from commit e99bfa9)
1 parent f4f4d2a commit f83447b

File tree

3 files changed

+35
-25
lines changed

3 files changed

+35
-25
lines changed

solver/cachekey.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,17 @@ func (ck *CacheKey) Output() Index {
5555
}
5656

5757
func (ck *CacheKey) clone() *CacheKey {
58+
ck.mu.RLock()
5859
nk := &CacheKey{
5960
ID: ck.ID,
6061
digest: ck.digest,
6162
vtx: ck.vtx,
6263
output: ck.output,
63-
ids: map[*cacheManager]string{},
64+
ids: make(map[*cacheManager]string, len(ck.ids)),
6465
}
6566
for cm, id := range ck.ids {
6667
nk.ids[cm] = id
6768
}
69+
ck.mu.RUnlock()
6870
return nk
6971
}

solver/combinedcache.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -101,34 +101,41 @@ func (cm *combinedCacheManager) Save(key *CacheKey, s Result, createdAt time.Tim
101101
}
102102

103103
func (cm *combinedCacheManager) Records(ctx context.Context, ck *CacheKey) ([]*CacheRecord, error) {
104+
ck.mu.RLock()
104105
if len(ck.ids) == 0 {
106+
ck.mu.RUnlock()
105107
return nil, errors.Errorf("no results")
106108
}
107109

110+
cms := make([]*cacheManager, 0, len(ck.ids))
111+
for cm := range ck.ids {
112+
cms = append(cms, cm)
113+
}
114+
ck.mu.RUnlock()
115+
108116
records := map[string]*CacheRecord{}
109117
var mu sync.Mutex
110118

111119
eg, _ := errgroup.WithContext(context.TODO())
112-
for c := range ck.ids {
113-
func(c *cacheManager) {
114-
eg.Go(func() error {
115-
recs, err := c.Records(ctx, ck)
116-
if err != nil {
117-
return err
118-
}
119-
mu.Lock()
120-
for _, rec := range recs {
121-
if _, ok := records[rec.ID]; !ok || c == cm.main {
122-
if c == cm.main {
123-
rec.Priority = 1
124-
}
125-
records[rec.ID] = rec
120+
for _, c := range cms {
121+
c := c
122+
eg.Go(func() error {
123+
recs, err := c.Records(ctx, ck)
124+
if err != nil {
125+
return err
126+
}
127+
mu.Lock()
128+
for _, rec := range recs {
129+
if _, ok := records[rec.ID]; !ok || c == cm.main {
130+
if c == cm.main {
131+
rec.Priority = 1
126132
}
133+
records[rec.ID] = rec
127134
}
128-
mu.Unlock()
129-
return nil
130-
})
131-
}(c)
135+
}
136+
mu.Unlock()
137+
return nil
138+
})
132139
}
133140

134141
if err := eg.Wait(); err != nil {

solver/exporter.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,9 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
8585
r CacheExporterRecord
8686
selector digest.Digest
8787
}
88+
k := e.k.clone() // protect against *CacheKey internal ids mutation from other exports
8889

89-
recKey := rootKey(e.k.Digest(), e.k.Output())
90+
recKey := rootKey(k.Digest(), k.Output())
9091
rec := t.Add(recKey)
9192
allRec := []CacheExporterRecord{rec}
9293

@@ -97,7 +98,7 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
9798
}
9899

99100
exportRecord := opt.ExportRoots
100-
if len(e.k.Deps()) > 0 {
101+
if len(deps) > 0 {
101102
exportRecord = true
102103
}
103104

@@ -126,7 +127,7 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
126127
if opt.CompressionOpt != nil {
127128
for _, r := range remotes { // record all remaining remotes as well
128129
rec := t.Add(recKey)
129-
rec.AddResult(e.k.vtx, int(e.k.output), v.CreatedAt, r)
130+
rec.AddResult(k.vtx, int(k.output), v.CreatedAt, r)
130131
variants = append(variants, rec)
131132
}
132133
}
@@ -147,15 +148,15 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
147148
if opt.CompressionOpt != nil {
148149
for _, r := range remotes { // record all remaining remotes as well
149150
rec := t.Add(recKey)
150-
rec.AddResult(e.k.vtx, int(e.k.output), v.CreatedAt, r)
151+
rec.AddResult(k.vtx, int(k.output), v.CreatedAt, r)
151152
variants = append(variants, rec)
152153
}
153154
}
154155
}
155156

156157
if remote != nil {
157158
for _, rec := range allRec {
158-
rec.AddResult(e.k.vtx, int(e.k.output), v.CreatedAt, remote)
159+
rec.AddResult(k.vtx, int(k.output), v.CreatedAt, remote)
159160
}
160161
}
161162
allRec = append(allRec, variants...)
@@ -198,7 +199,7 @@ func (e *exporter) ExportTo(ctx context.Context, t CacheExporterTarget, opt Cach
198199
}
199200
}
200201

201-
for cm, id := range e.k.ids {
202+
for cm, id := range k.ids {
202203
if _, err := addBacklinks(t, rec, cm, id, bkm); err != nil {
203204
return nil, err
204205
}

0 commit comments

Comments
 (0)