github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/symbolizer/cache.go (about) 1 // Copyright 2024 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package symbolizer 5 6 import ( 7 "strings" 8 "sync" 9 ) 10 11 // Cache caches symbolization results from Symbolizer in a thread-safe way. 12 type Cache struct { 13 mu sync.RWMutex 14 cache map[cacheKey]cacheVal 15 } 16 17 type cacheKey struct { 18 bin string 19 pc uint64 20 } 21 22 type cacheVal struct { 23 frames []Frame 24 err error 25 } 26 27 func (c *Cache) Symbolize(inner func(string, ...uint64) ([]Frame, error), bin string, pc uint64) ([]Frame, error) { 28 key := cacheKey{bin, pc} 29 c.mu.RLock() 30 val, ok := c.cache[key] 31 c.mu.RUnlock() 32 if ok { 33 return val.frames, val.err 34 } 35 frames, err := inner(bin, pc) 36 c.mu.Lock() 37 if c.cache == nil { 38 c.cache = make(map[cacheKey]cacheVal) 39 } 40 c.cache[key] = cacheVal{frames, err} 41 c.mu.Unlock() 42 return frames, err 43 } 44 45 // Interner allows to intern/deduplicate strings. 46 // Interner.Do semantically returns the same string, but physically it will point 47 // to an existing string with the same contents (if there was one passed to Do in the past). 48 // Interned strings are also "cloned", that is, if the passed string points to a large 49 // buffer, it won't after interning (and won't prevent GC'ing of the large buffer). 50 // The type is not thread-safe. 51 type Interner struct { 52 m sync.Map 53 } 54 55 func (in *Interner) Do(s string) string { 56 if interned, ok := in.m.Load(s); ok { 57 return interned.(string) 58 } 59 s = strings.Clone(s) 60 in.m.Store(s, s) 61 return s 62 }