]> Cypherpunks.ru repositories - gostls13.git/blob - misc/cgo/testsanitizers/libfuzzer_test.go
misc/cgo/testsanitizers: add libfuzzer tests
[gostls13.git] / misc / cgo / testsanitizers / libfuzzer_test.go
1 // Copyright 2022 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package sanitizers_test
6
7 import (
8         "strings"
9         "testing"
10 )
11
12 func TestLibFuzzer(t *testing.T) {
13         goos, err := goEnv("GOOS")
14         if err != nil {
15                 t.Fatal(err)
16         }
17         goarch, err := goEnv("GOARCH")
18         if err != nil {
19                 t.Fatal(err)
20         }
21         if !libFuzzerSupported(goos, goarch) {
22                 t.Skipf("skipping on %s/%s; libfuzzer option is not supported.", goos, goarch)
23         }
24         config := configure("fuzzer")
25         config.skipIfCSanitizerBroken(t)
26
27         cases := []struct {
28                 goSrc         string
29                 cSrc          string
30                 expectedError string
31         }{
32                 {goSrc: "libfuzzer1.go", expectedError: "panic: found it"},
33                 {goSrc: "libfuzzer2.go", cSrc: "libfuzzer2.c", expectedError: "panic: found it"},
34         }
35         for _, tc := range cases {
36                 tc := tc
37                 name := strings.TrimSuffix(tc.goSrc, ".go")
38                 t.Run(name, func(t *testing.T) {
39                         t.Parallel()
40
41                         dir := newTempDir(t)
42                         defer dir.RemoveAll(t)
43
44                         // build Go code in libfuzzer mode to a c-archive
45                         outPath := dir.Join(name)
46                         archivePath := dir.Join(name + ".a")
47                         mustRun(t, config.goCmd("build", "-buildmode=c-archive", "-o", archivePath, srcPath(tc.goSrc)))
48
49                         // build C code (if any) and link with Go code
50                         cmd, err := cc(config.cFlags...)
51                         if err != nil {
52                                 t.Fatalf("error running cc: %v", err)
53                         }
54                         cmd.Args = append(cmd.Args, config.ldFlags...)
55                         cmd.Args = append(cmd.Args, "-o", outPath, "-I", dir.Base())
56                         if tc.cSrc != "" {
57                                 cmd.Args = append(cmd.Args, srcPath(tc.cSrc))
58                         }
59                         cmd.Args = append(cmd.Args, archivePath)
60                         mustRun(t, cmd)
61
62                         cmd = hangProneCmd(outPath)
63                         outb, err := cmd.CombinedOutput()
64                         out := string(outb)
65                         if err == nil {
66                                 t.Fatalf("fuzzing succeeded unexpectedly; output:\n%s", out)
67                         }
68                         if !strings.Contains(out, tc.expectedError) {
69                                 t.Errorf("exited without expected error %q; got\n%s", tc.expectedError, out)
70                         }
71                 })
72         }
73 }
74
75 // libFuzzerSupported is a copy of the function internal/platform.FuzzInstrumented,
76 // because the internal package can't be used here.
77 func libFuzzerSupported(goos, goarch string) bool {
78         switch goarch {
79         case "amd64", "arm64":
80                 // TODO(#14565): support more architectures.
81                 switch goos {
82                 case "darwin", "freebsd", "linux", "windows":
83                         return true
84                 default:
85                         return false
86                 }
87         default:
88                 return false
89         }
90 }