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  }