aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/runtest
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2025-09-19 11:41:43 +0200
committerAlexander Potapenko <glider@google.com>2025-09-22 08:48:11 +0000
commit4688d9460dff255a905637c5120faad7be4f0329 (patch)
tree2972cb9ca5eb33356ac17c389819ad11c6cf219a /pkg/runtest
parenta858c6613a23b0b2a91b35d8695ef93b7640755b (diff)
pkg/runtest: refactor checkCallResult()
Break checkCallResult() down into smaller functions, checkCallStatus() and checkCallCoverage().
Diffstat (limited to 'pkg/runtest')
-rw-r--r--pkg/runtest/run.go90
1 files changed, 54 insertions, 36 deletions
diff --git a/pkg/runtest/run.go b/pkg/runtest/run.go
index f242fa137..ffd791c68 100644
--- a/pkg/runtest/run.go
+++ b/pkg/runtest/run.go
@@ -20,7 +20,6 @@ import (
"path/filepath"
"regexp"
"runtime"
- "slices"
"sort"
"strconv"
"strings"
@@ -33,6 +32,13 @@ import (
"github.com/google/syzkaller/sys/targets"
)
+// Pseudo-syscalls that might not provide any coverage when invoked.
+var noCovSyscalls = map[string]struct{}{
+ "syz_btf_id_by_name": {},
+ "syz_kvm_assert_syzos_uexit": {},
+ "syz_kvm_assert_syzos_kvm_exit": {},
+}
+
type runRequest struct {
*queue.Request
sourceOpts *csource.Options
@@ -521,17 +527,24 @@ func checkResult(req *runRequest) error {
func checkCallResult(req *runRequest, isC bool, run, call int, info *flatrpc.ProgInfo, calls map[string]bool) error {
inf := info.Calls[call]
want := req.results.Calls[call]
+ if err := checkCallStatus(req, isC, run, call, inf, want); err != nil {
+ return err
+ }
+ if isC || inf.Flags&flatrpc.CallFlagExecuted == 0 {
+ return nil
+ }
+ // We check coverage only for syz-executor.
+ return checkCallCoverage(req, run, call, info, calls)
+}
+
+func checkCallStatus(req *runRequest, isC bool, run, call int, inf, want *flatrpc.CallInfo) error {
+ // In non-threaded mode blocked syscalls will block the main thread
+ // and we won't detect blocked/unfinished syscalls.
+ // C code also does not detect blocked/non-finished calls.
+ ignoreFlags := isC || req.ExecOpts.ExecFlags&flatrpc.ExecFlagThreaded == 0
for flag, what := range flatrpc.EnumNamesCallFlag {
- if flag != flatrpc.CallFlagFinished {
- if isC {
- // C code does not detect blocked/non-finished calls.
- continue
- }
- if req.ExecOpts.ExecFlags&flatrpc.ExecFlagThreaded == 0 {
- // In non-threaded mode blocked syscalls will block main thread
- // and we won't detect blocked/unfinished syscalls.
- continue
- }
+ if ignoreFlags && flag != flatrpc.CallFlagFinished {
+ continue
}
if runtime.GOOS == targets.FreeBSD && flag == flatrpc.CallFlagBlocked {
// Blocking detection is flaky on freebsd.
@@ -539,42 +552,47 @@ func checkCallResult(req *runRequest, isC bool, run, call int, info *flatrpc.Pro
continue
}
if (inf.Flags^want.Flags)&flag != 0 {
- not := " not"
- if inf.Flags&flag != 0 {
- not = ""
- }
- return fmt.Errorf("run %v: call %v is%v %v", run, call, not, what)
+ return fmt.Errorf("run %v: call %v %v %v, want %v",
+ run, call, flagStatus(inf.Flags, flag), what, flagStatus(want.Flags, flag))
}
}
if inf.Flags&flatrpc.CallFlagFinished != 0 && inf.Error != want.Error {
return fmt.Errorf("run %v: wrong call %v result %v, want %v",
run, call, inf.Error, want.Error)
}
- if isC || inf.Flags&flatrpc.CallFlagExecuted == 0 {
- return nil
+ return nil
+}
+
+func flagStatus(flags, flag flatrpc.CallFlag) string {
+ if flags&flag != 0 {
+ return "is"
}
- if req.ExecOpts.EnvFlags&flatrpc.ExecEnvSignal != 0 {
- callName := req.Prog.Calls[call].Meta.CallName
- // Pseudo-syscalls that might not provide any coverage when invoked.
- noCovSyscalls := []string{"syz_btf_id_by_name", "syz_kvm_assert_syzos_uexit", "syz_kvm_assert_syzos_kvm_exit"}
- isNoCov := slices.Contains(noCovSyscalls, callName)
- // Signal is always deduplicated, so we may not get any signal
- // on a second invocation of the same syscall.
- // For calls that are not meant to collect synchronous coverage we
- // allow the signal to be empty as long as the extra signal is not.
- if !isNoCov && len(inf.Signal) < 2 && !calls[callName] &&
- len(info.Extra.Signal) == 0 {
- return fmt.Errorf("run %v: call %v: no signal", run, call)
- }
- if !isNoCov && len(inf.Cover) == 0 {
- return fmt.Errorf("run %v: call %v: no cover", run, call)
- }
- calls[callName] = true
- } else {
+ return "is not"
+}
+
+func checkCallCoverage(req *runRequest, run, call int, info *flatrpc.ProgInfo, calls map[string]bool) error {
+ inf := info.Calls[call]
+ if req.ExecOpts.EnvFlags&flatrpc.ExecEnvSignal == 0 {
if len(inf.Signal) != 0 {
return fmt.Errorf("run %v: call %v: got %v unwanted signal", run, call, len(inf.Signal))
}
+ return nil
+ }
+ callName := req.Prog.Calls[call].Meta.CallName
+ _, isNoCov := noCovSyscalls[callName]
+ // Signal is always deduplicated, so we may not get any signal
+ // on a second invocation of the same syscall.
+ // For calls that are not meant to collect synchronous coverage we
+ // allow the signal to be empty as long as the extra signal is not.
+ if !isNoCov && !calls[callName] {
+ if len(inf.Signal) < 2 && len(info.Extra.Signal) == 0 {
+ return fmt.Errorf("run %v: call %v: no signal", run, call)
+ }
+ }
+ if !isNoCov && len(inf.Cover) == 0 {
+ return fmt.Errorf("run %v: call %v: no cover", run, call)
}
+ calls[callName] = true
return nil
}