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 4package csource 5 6import ( 7 "bytes" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 13 "github.com/google/syzkaller/pkg/osutil" 14 "github.com/google/syzkaller/prog" 15 "github.com/google/syzkaller/sys/targets" 16) 17 18// Build builds a C program from source src and returns name of the resulting binary. 19func Build(target *prog.Target, src []byte) (string, error) { 20 return build(target, src, "") 21} 22 23// BuildFile builds a C/C++ program from file src and returns name of the resulting binary. 24func BuildFile(target *prog.Target, src string) (string, error) { 25 return build(target, nil, src) 26} 27 28func build(target *prog.Target, src []byte, file string) (string, error) { 29 sysTarget := targets.Get(target.OS, target.Arch) 30 compiler := sysTarget.CCompiler 31 if _, err := exec.LookPath(compiler); err != nil { 32 return "", fmt.Errorf("no target compiler %v", compiler) 33 } 34 // We call the binary syz-executor because it sometimes shows in bug titles, 35 // and we don't want 2 different bugs for when a crash is triggered during fuzzing and during repro. 36 bin, err := osutil.TempFile("syz-executor") 37 if err != nil { 38 return "", err 39 } 40 41 flags := []string{ 42 "-Wall", "-Werror", "-O1", "-g", "-o", bin, "-pthread", 43 "-DGOOS_" + target.OS + "=1", 44 "-DGOARCH_" + target.Arch + "=1", 45 } 46 if file == "" { 47 flags = append(flags, "-x", "c", "-") 48 } else { 49 flags = append(flags, file) 50 } 51 flags = append(flags, sysTarget.CrossCFlags...) 52 if sysTarget.PtrSize == 4 { 53 // We do generate uint64's for syscall arguments that overflow longs on 32-bit archs. 54 flags = append(flags, "-Wno-overflow") 55 } 56 cmd := osutil.Command(compiler, flags...) 57 if file == "" { 58 cmd.Stdin = bytes.NewReader(src) 59 } 60 out, err := cmd.CombinedOutput() 61 if err != nil { 62 os.Remove(bin) 63 if file != "" { 64 src, _ = ioutil.ReadFile(file) 65 } 66 return "", fmt.Errorf("failed to build program:\n%s\n%s\ncompiler invocation: %v %v", 67 src, out, compiler, flags) 68 } 69 return bin, nil 70} 71 72// Format reformats C source using clang-format. 73func Format(src []byte) ([]byte, error) { 74 stdout, stderr := new(bytes.Buffer), new(bytes.Buffer) 75 cmd := osutil.Command("clang-format", "-assume-filename=/src.c", "-style", style) 76 cmd.Stdin = bytes.NewReader(src) 77 cmd.Stdout = stdout 78 cmd.Stderr = stderr 79 if err := cmd.Run(); err != nil { 80 return src, fmt.Errorf("failed to format source: %v\n%v", err, stderr.String()) 81 } 82 return stdout.Bytes(), nil 83} 84 85// Something acceptable for kernel developers and email-friendly. 86var style = `{ 87BasedOnStyle: LLVM, 88IndentWidth: 2, 89UseTab: Never, 90BreakBeforeBraces: Linux, 91IndentCaseLabels: false, 92DerivePointerAlignment: false, 93PointerAlignment: Left, 94AlignTrailingComments: true, 95AllowShortBlocksOnASingleLine: false, 96AllowShortCaseLabelsOnASingleLine: false, 97AllowShortFunctionsOnASingleLine: false, 98AllowShortIfStatementsOnASingleLine: false, 99AllowShortLoopsOnASingleLine: false, 100ColumnLimit: 80, 101}` 102