1// Copyright 2015 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 4package ipc_test 5 6import ( 7 "fmt" 8 "math/rand" 9 "os" 10 "path/filepath" 11 "runtime" 12 "testing" 13 "time" 14 15 "github.com/google/syzkaller/pkg/csource" 16 . "github.com/google/syzkaller/pkg/ipc" 17 "github.com/google/syzkaller/pkg/ipc/ipcconfig" 18 "github.com/google/syzkaller/pkg/osutil" 19 "github.com/google/syzkaller/prog" 20 _ "github.com/google/syzkaller/sys" 21) 22 23const timeout = 10 * time.Second 24 25func buildExecutor(t *testing.T, target *prog.Target) string { 26 src := filepath.FromSlash("../../executor/executor.cc") 27 bin, err := csource.BuildFile(target, src) 28 if err != nil { 29 t.Fatal(err) 30 } 31 return bin 32} 33 34func initTest(t *testing.T) (*prog.Target, rand.Source, int, EnvFlags) { 35 t.Parallel() 36 iters := 100 37 if testing.Short() { 38 iters = 10 39 } 40 seed := int64(time.Now().UnixNano()) 41 rs := rand.NewSource(seed) 42 t.Logf("seed=%v", seed) 43 target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH) 44 if err != nil { 45 t.Fatal(err) 46 } 47 cfg, _, err := ipcconfig.Default(target) 48 if err != nil { 49 t.Fatal(err) 50 } 51 flags := cfg.Flags & (FlagUseShmem | FlagUseForkServer) 52 return target, rs, iters, flags 53} 54 55// TestExecutor runs all internal executor unit tests. 56// We do it here because we already build executor binary here. 57func TestExecutor(t *testing.T) { 58 target, err := prog.GetTarget(runtime.GOOS, runtime.GOARCH) 59 if err != nil { 60 t.Fatal(err) 61 } 62 bin := buildExecutor(t, target) 63 defer os.Remove(bin) 64 output, err := osutil.RunCmd(time.Minute, "", bin, "test") 65 if err != nil { 66 t.Fatal(err) 67 } 68 t.Logf("executor output:\n%s", output) 69} 70 71func TestExecute(t *testing.T) { 72 target, _, _, configFlags := initTest(t) 73 74 bin := buildExecutor(t, target) 75 defer os.Remove(bin) 76 77 flags := []ExecFlags{0, FlagThreaded, FlagThreaded | FlagCollide} 78 for _, flag := range flags { 79 t.Logf("testing flags 0x%x\n", flag) 80 cfg := &Config{ 81 Executor: bin, 82 Flags: configFlags, 83 Timeout: timeout, 84 } 85 env, err := MakeEnv(cfg, 0) 86 if err != nil { 87 t.Fatalf("failed to create env: %v", err) 88 } 89 defer env.Close() 90 91 for i := 0; i < 10; i++ { 92 p := target.GenerateSimpleProg() 93 opts := &ExecOpts{ 94 Flags: flag, 95 } 96 output, info, failed, hanged, err := env.Exec(opts, p) 97 if err != nil { 98 t.Fatalf("failed to run executor: %v", err) 99 } 100 if hanged { 101 t.Fatalf("program hanged:\n%s", output) 102 } 103 if failed { 104 t.Fatalf("program failed:\n%s", output) 105 } 106 if len(info) == 0 { 107 t.Fatalf("no calls executed:\n%s", output) 108 } 109 if info[0].Errno != 0 { 110 t.Fatalf("simple call failed: %v\n%s", info[0].Errno, output) 111 } 112 if len(output) != 0 { 113 t.Fatalf("output on empty program") 114 } 115 } 116 } 117} 118 119func TestParallel(t *testing.T) { 120 target, _, _, configFlags := initTest(t) 121 bin := buildExecutor(t, target) 122 defer os.Remove(bin) 123 cfg := &Config{ 124 Executor: bin, 125 Flags: configFlags, 126 } 127 const P = 10 128 errs := make(chan error, P) 129 for p := 0; p < P; p++ { 130 go func() { 131 env, err := MakeEnv(cfg, 0) 132 if err != nil { 133 errs <- fmt.Errorf("failed to create env: %v", err) 134 return 135 } 136 defer func() { 137 env.Close() 138 errs <- err 139 }() 140 p := target.GenerateSimpleProg() 141 opts := &ExecOpts{} 142 output, info, failed, hanged, err := env.Exec(opts, p) 143 if err != nil { 144 err = fmt.Errorf("failed to run executor: %v", err) 145 return 146 } 147 if hanged { 148 err = fmt.Errorf("program hanged:\n%s", output) 149 return 150 } 151 if failed { 152 err = fmt.Errorf("program failed:\n%s", output) 153 return 154 } 155 if len(info) == 0 { 156 err = fmt.Errorf("no calls executed:\n%s", output) 157 return 158 } 159 if info[0].Errno != 0 { 160 err = fmt.Errorf("simple call failed: %v\n%s", info[0].Errno, output) 161 return 162 } 163 if len(output) != 0 { 164 err = fmt.Errorf("output on empty program") 165 return 166 } 167 }() 168 } 169 for p := 0; p < P; p++ { 170 if err := <-errs; err != nil { 171 t.Fatal(err) 172 } 173 } 174} 175