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 }