github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/csource/build.go (about) 1 // Copyright 2017 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 package csource 5 6 import ( 7 "bytes" 8 "fmt" 9 "os" 10 "path/filepath" 11 "runtime" 12 "strings" 13 "testing" 14 15 "github.com/google/syzkaller/pkg/osutil" 16 "github.com/google/syzkaller/prog" 17 "github.com/google/syzkaller/sys/targets" 18 ) 19 20 // Build builds a C program from source src and returns name of the resulting binary. 21 func Build(target *prog.Target, src []byte) (string, error) { 22 return build(target, src, "", "") 23 } 24 25 // BuildNoWarn is the same as Build, but ignores all compilation warnings. 26 // Should not be used in tests, but may be used e.g. when we are bisecting and potentially 27 // using an old repro with newer compiler, or a compiler that we never seen before. 28 // In these cases it's more important to build successfully. 29 func BuildNoWarn(target *prog.Target, src []byte) (string, error) { 30 return build(target, src, "", "", "-fpermissive", "-w") 31 } 32 33 // BuildExecutor builds the executor binary for tests. 34 // rootDir must point to syzkaller root directory in slash notation. 35 func BuildExecutor(t *testing.T, target *prog.Target, rootDir string, cflags ...string) string { 36 // Build w/o optimizations for tests. Tests can build lots of versions of executor in parallel, 37 // and on overloaded machines it can be slow. On my machine this reduces executor build time 38 // from ~7.5 to ~3.5 secs. 39 cflags = append(cflags, "-O0") 40 bin, err := build(target, nil, filepath.FromSlash(rootDir), 41 filepath.FromSlash("executor/executor.cc"), cflags...) 42 if err != nil { 43 t.Fatalf("failed to build executor: %v", err) 44 } 45 t.Cleanup(func() { 46 os.Remove(bin) 47 }) 48 return bin 49 } 50 51 func build(target *prog.Target, src []byte, dir, file string, cflags ...string) (string, error) { 52 // We call the binary syz-executor because it sometimes shows in bug titles, 53 // and we don't want 2 different bugs for when a crash is triggered during fuzzing and during repro. 54 bin, err := osutil.TempFile("syz-executor") 55 if err != nil { 56 return "", err 57 } 58 59 flags := []string{ 60 "-o", bin, 61 "-DGOOS_" + target.OS + "=1", 62 "-DGOARCH_" + target.Arch + "=1", 63 "-DHOSTGOOS_" + runtime.GOOS + "=1", 64 } 65 if file == "" { 66 flags = append(flags, "-x", "c", "-") 67 } else { 68 flags = append(flags, file) 69 } 70 sysTarget := targets.Get(target.OS, target.Arch) 71 compiler, targetCFlags := sysTarget.CCompiler, sysTarget.CFlags 72 if file != "" && !strings.HasSuffix(file, ".c") { 73 compiler, targetCFlags = sysTarget.CxxCompiler, sysTarget.CxxFlags 74 } 75 flags = append(flags, targetCFlags...) 76 flags = append(flags, cflags...) 77 if sysTarget.PtrSize == 4 { 78 // We do generate uint64's for syscall arguments that overflow longs on 32-bit archs. 79 flags = append(flags, "-Wno-overflow") 80 } 81 cmd := osutil.Command(compiler, flags...) 82 cmd.Dir = dir 83 if file == "" { 84 cmd.Stdin = bytes.NewReader(src) 85 } 86 out, err := cmd.CombinedOutput() 87 if err != nil { 88 os.Remove(bin) 89 if file != "" { 90 src, _ = os.ReadFile(file) 91 } 92 return "", fmt.Errorf("failed to build program:\n%s\n%s\ncompiler invocation: %v %v", 93 src, out, compiler, flags) 94 } 95 return bin, nil 96 } 97 98 // Format reformats C source using clang-format. 99 func Format(src []byte) ([]byte, error) { 100 stdout, stderr := new(bytes.Buffer), new(bytes.Buffer) 101 cmd := osutil.Command("clang-format", "-assume-filename=/src.c", "-style", style) 102 cmd.Stdin = bytes.NewReader(src) 103 cmd.Stdout = stdout 104 cmd.Stderr = stderr 105 if err := cmd.Run(); err != nil { 106 return src, fmt.Errorf("failed to format source: %w\n%v", err, stderr.String()) 107 } 108 return stdout.Bytes(), nil 109 } 110 111 // Something acceptable for kernel developers and email-friendly. 112 var style = `{ 113 BasedOnStyle: LLVM, 114 IndentWidth: 2, 115 UseTab: Never, 116 BreakBeforeBraces: Linux, 117 IndentCaseLabels: false, 118 DerivePointerAlignment: false, 119 PointerAlignment: Left, 120 AlignTrailingComments: true, 121 AllowShortBlocksOnASingleLine: false, 122 AllowShortCaseLabelsOnASingleLine: false, 123 AllowShortFunctionsOnASingleLine: false, 124 AllowShortIfStatementsOnASingleLine: false, 125 AllowShortLoopsOnASingleLine: false, 126 ColumnLimit: 80, 127 }`