github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-verifier/exectask.go (about)

     1  // Copyright 2021 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  // TODO: switch syz-verifier to use syz-fuzzer.
     5  
     6  //go:build ignore
     7  
     8  package main
     9  
    10  import (
    11  	"container/heap"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"github.com/google/syzkaller/pkg/rpctype"
    17  	"github.com/google/syzkaller/prog"
    18  )
    19  
    20  type EnvDescr int64
    21  
    22  const (
    23  	AnyEnvironment EnvDescr = iota
    24  	NewEnvironment
    25  	// TODO: add CleanVMEnvironment support.
    26  
    27  	EnvironmentsCount
    28  )
    29  
    30  // ExecTask is the atomic analysis entity. Once executed, it could trigger the
    31  // pipeline propagation for the program.
    32  type ExecTask struct {
    33  	CreationTime   time.Time
    34  	Program        *prog.Prog
    35  	ID             int64
    36  	ExecResultChan ExecResultChan
    37  
    38  	priority int // The priority of the item in the queue.
    39  	// The index is needed by update and is maintained by the heap.Interface methods.
    40  	index int // The index of the item in the heap.
    41  }
    42  
    43  func (t *ExecTask) ToRPC() *rpctype.ExecTask {
    44  	return &rpctype.ExecTask{
    45  		Prog: t.Program.Serialize(),
    46  		ID:   t.ID,
    47  	}
    48  }
    49  
    50  type ExecTaskFactory struct {
    51  	chanMapMutex           sync.Mutex
    52  	taskIDToExecResultChan map[int64]ExecResultChan
    53  	taskCounter            int64
    54  }
    55  
    56  func MakeExecTaskFactory() *ExecTaskFactory {
    57  	return &ExecTaskFactory{
    58  		taskIDToExecResultChan: make(map[int64]ExecResultChan),
    59  		taskCounter:            -1,
    60  	}
    61  }
    62  
    63  type ExecResultChan chan *ExecResult
    64  
    65  func (factory *ExecTaskFactory) MakeExecTask(prog *prog.Prog) *ExecTask {
    66  	task := &ExecTask{
    67  		CreationTime:   time.Now(),
    68  		Program:        prog,
    69  		ExecResultChan: make(ExecResultChan),
    70  		ID:             atomic.AddInt64(&factory.taskCounter, 1),
    71  	}
    72  
    73  	factory.chanMapMutex.Lock()
    74  	defer factory.chanMapMutex.Unlock()
    75  	factory.taskIDToExecResultChan[task.ID] = task.ExecResultChan
    76  
    77  	return task
    78  }
    79  
    80  func (factory *ExecTaskFactory) ExecTasksQueued() int {
    81  	factory.chanMapMutex.Lock()
    82  	defer factory.chanMapMutex.Unlock()
    83  	return len(factory.taskIDToExecResultChan)
    84  }
    85  
    86  func (factory *ExecTaskFactory) DeleteExecTask(task *ExecTask) {
    87  	factory.chanMapMutex.Lock()
    88  	defer factory.chanMapMutex.Unlock()
    89  	delete(factory.taskIDToExecResultChan, task.ID)
    90  }
    91  
    92  func (factory *ExecTaskFactory) GetExecResultChan(taskID int64) ExecResultChan {
    93  	factory.chanMapMutex.Lock()
    94  	defer factory.chanMapMutex.Unlock()
    95  
    96  	return factory.taskIDToExecResultChan[taskID]
    97  }
    98  
    99  func MakeExecTaskQueue() *ExecTaskQueue {
   100  	return &ExecTaskQueue{
   101  		pq: make(ExecTaskPriorityQueue, 0),
   102  	}
   103  }
   104  
   105  // ExecTaskQueue respects the pq.priority. Internally it is a thread-safe PQ.
   106  type ExecTaskQueue struct {
   107  	pq ExecTaskPriorityQueue
   108  	mu sync.Mutex
   109  }
   110  
   111  // PopTask return false if no tasks are available.
   112  func (q *ExecTaskQueue) PopTask() (*ExecTask, bool) {
   113  	q.mu.Lock()
   114  	defer q.mu.Unlock()
   115  	if q.pq.Len() == 0 {
   116  		return nil, false
   117  	}
   118  	return heap.Pop(&q.pq).(*ExecTask), true
   119  }
   120  
   121  func (q *ExecTaskQueue) PushTask(task *ExecTask) {
   122  	q.mu.Lock()
   123  	defer q.mu.Unlock()
   124  	heap.Push(&q.pq, task)
   125  }
   126  
   127  func (q *ExecTaskQueue) Len() int {
   128  	q.mu.Lock()
   129  	defer q.mu.Unlock()
   130  	return q.pq.Len()
   131  }
   132  
   133  // ExecTaskPriorityQueue reused example from https://pkg.go.dev/container/heap
   134  type ExecTaskPriorityQueue []*ExecTask
   135  
   136  func (pq ExecTaskPriorityQueue) Len() int { return len(pq) }
   137  
   138  func (pq ExecTaskPriorityQueue) Less(i, j int) bool {
   139  	// We want Pop to give us the highest, not lowest, priority so we use greater than here.
   140  	return pq[i].priority > pq[j].priority
   141  }
   142  
   143  func (pq ExecTaskPriorityQueue) Swap(i, j int) {
   144  	pq[i], pq[j] = pq[j], pq[i]
   145  	pq[i].index = i
   146  	pq[j].index = j
   147  }
   148  
   149  func (pq *ExecTaskPriorityQueue) Push(x interface{}) {
   150  	n := len(*pq)
   151  	item := x.(*ExecTask)
   152  	item.index = n
   153  	*pq = append(*pq, item)
   154  }
   155  
   156  func (pq *ExecTaskPriorityQueue) Pop() interface{} {
   157  	old := *pq
   158  	n := len(old)
   159  	item := old[n-1]
   160  	old[n-1] = nil  // avoid memory leak
   161  	item.index = -1 // for safety
   162  	*pq = old[0 : n-1]
   163  	return item
   164  }