github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/subsystem/linux/path_coincidence.go (about)

     1  // Copyright 2023 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 linux
     5  
     6  import (
     7  	"io/fs"
     8  	"regexp"
     9  	"runtime"
    10  	"sync"
    11  
    12  	"github.com/google/syzkaller/pkg/subsystem"
    13  )
    14  
    15  func BuildCoincidenceMatrix(root fs.FS, list []*subsystem.Subsystem,
    16  	excludeRe *regexp.Regexp) (*CoincidenceMatrix, error) {
    17  	// Create a matcher.
    18  	matcher := subsystem.MakePathMatcher(list)
    19  	chPaths, chResult := extractSubsystems(matcher)
    20  	// The final consumer goroutine.
    21  	cm := MakeCoincidenceMatrix()
    22  	ready := make(chan struct{})
    23  	go func() {
    24  		for items := range chResult {
    25  			cm.Record(items...)
    26  		}
    27  		ready <- struct{}{}
    28  	}()
    29  	// Source of data.
    30  	err := fs.WalkDir(root, ".", func(path string, info fs.DirEntry, err error) error {
    31  		if err != nil || info.IsDir() {
    32  			return err
    33  		}
    34  		if !includePathRe.MatchString(path) ||
    35  			(excludeRe != nil && excludeRe.MatchString(path)) {
    36  			return nil
    37  		}
    38  		chPaths <- path
    39  		return nil
    40  	})
    41  	close(chPaths)
    42  	<-ready
    43  	return cm, err
    44  }
    45  
    46  var (
    47  	includePathRe = regexp.MustCompile(`(?:/|\.(?:c|h|S))$`)
    48  )
    49  
    50  func extractSubsystems(matcher *subsystem.PathMatcher) (chan<- string, <-chan []*subsystem.Subsystem) {
    51  	procs := runtime.NumCPU()
    52  	paths, output := make(chan string, procs), make(chan []*subsystem.Subsystem, procs)
    53  	var wg sync.WaitGroup
    54  	for i := 0; i < procs; i++ {
    55  		wg.Add(1)
    56  		go func() {
    57  			defer wg.Done()
    58  			for path := range paths {
    59  				output <- matcher.Match(path)
    60  			}
    61  		}()
    62  	}
    63  	go func() {
    64  		wg.Wait()
    65  		close(output)
    66  	}()
    67  	return paths, output
    68  }