github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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 map[string]string 53 } 54 55 func (in *Interner) Do(s string) string { 56 if in.m == nil { 57 in.m = make(map[string]string) 58 } 59 if interned, ok := in.m[s]; ok { 60 return interned 61 } 62 s = strings.Clone(s) 63 in.m[s] = s 64 return s 65 }