code-intelligence.com/cifuzz@v0.40.0/internal/build/build.go (about) 1 package build 2 3 import ( 4 "os" 5 "runtime" 6 7 "github.com/Masterminds/semver" 8 9 "code-intelligence.com/cifuzz/util/envutil" 10 ) 11 12 type Result struct { 13 // A name which uniquely identifies the fuzz test and is a valid path 14 Name string 15 // Optional name for the fuzz test target method 16 TargetMethod string 17 // Canonical path of the fuzz test executable 18 Executable string 19 // Canonical path of the fuzz test's generated corpus directory 20 GeneratedCorpus string 21 // Canonical path of the fuzz test's default seed corpus directory 22 SeedCorpus string 23 // Canonical path of the build directory 24 BuildDir string 25 // The sanitizers with which the fuzz test was built 26 Sanitizers []string 27 // The canonical paths of the fuzz test's runtime dependencies 28 RuntimeDeps []string 29 // Canonical path of the directory to which source file paths should 30 // be made relative 31 ProjectDir string 32 } 33 34 func CommonBuildEnv() ([]string, error) { 35 var err error 36 env := os.Environ() 37 38 // Set CIFUZZ=1 to allow the build system to figure out that it was 39 // started by cifuzz. 40 env, err = envutil.Setenv(env, "CIFUZZ", "1") 41 if err != nil { 42 return nil, err 43 } 44 45 // On Windows, our preferred compiler is clang-cl, which can't easily be run 46 // from an arbitrary terminal as it requires about a dozen environment 47 // variables to be set correctly. Thus, we assume users to run cifuzz from 48 // a developer command prompt anyway and thus don't need to set the 49 // compiler explicitly. 50 if runtime.GOOS != "windows" { 51 // Set the C/C++ compiler to clang/clang++ (if not already set), 52 // which is needed to build a binary with fuzzing instrumentation 53 // gcc doesn't have -fsanitize=fuzzer. 54 if val := envutil.GetEnvWithPathSubstring(env, "CC", "clang"); val == "" { 55 env, err = envutil.Setenv(env, "CC", "clang") 56 if err != nil { 57 return nil, err 58 } 59 } 60 if val := envutil.GetEnvWithPathSubstring(env, "CXX", "clang++"); val == "" { 61 env, err = envutil.Setenv(env, "CXX", "clang++") 62 if err != nil { 63 return nil, err 64 } 65 } 66 } 67 68 // We don't want to fail if ASan is set up incorrectly for tools 69 // built and executed during the build or they contain leaks. 70 env, err = envutil.Setenv(env, "ASAN_OPTIONS", "detect_leaks=0:verify_asan_link_order=0") 71 if err != nil { 72 return nil, err 73 } 74 75 return env, nil 76 } 77 78 var commonCFlags = []string{ 79 // Keep debug symbols 80 "-g", 81 // Do optimizations which don't harm debugging 82 "-Og", 83 // To get good stack frames for better debugging 84 "-fno-omit-frame-pointer", 85 // Conventional macro to conditionally compile out fuzzer road blocks 86 // See https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode 87 "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION", 88 // Ensure that asserts are enabled regardless of compilation mode (e.g. explicit -DNDEBUG). 89 "-UNDEBUG", 90 } 91 92 func LibFuzzerCFlags() []string { 93 // These flags must not contain spaces, because the environment 94 // variables that are set to these flags are space separated. 95 // Note: Keep in sync with share/cmake/cifuzz-functions.cmake 96 return append(commonCFlags, []string{ 97 // ----- Flags used to build with libFuzzer ----- 98 // Compile with edge coverage and compare instrumentation. We 99 // use fuzzer-no-link here instead of -fsanitize=fuzzer because 100 // CFLAGS are often also passed to the linker, which would cause 101 // errors if the build includes tools which have a main function. 102 "-fsanitize=fuzzer-no-link", 103 104 // ----- Flags used to build with ASan ----- 105 // Build with instrumentation for ASan and UBSan and link in 106 // their runtime 107 "-fsanitize=address,undefined", 108 // To support recovering from ASan findings 109 "-fsanitize-recover=address", 110 // Use additional error detectors for use-after-scope bugs 111 // TODO: Evaluate the slow down caused by this flag 112 // TODO: Check if there are other additional error detectors 113 // which we want to use 114 "-fsanitize-address-use-after-scope", 115 // Disable source fortification, which is currently not supported 116 // in combination with ASan, see https://github.com/google/sanitizers/issues/247 117 "-U_FORTIFY_SOURCE", 118 }...) 119 } 120 121 func CoverageCFlags(clangVersion *semver.Version) []string { 122 cflags := append(commonCFlags, []string{ 123 // ----- Flags used to build with code coverage ----- 124 "-fprofile-instr-generate", 125 "-fcoverage-mapping", 126 // Disable source fortification to ensure that coverage builds 127 // reach all code reached by ASan builds. 128 "-U_FORTIFY_SOURCE", 129 }...) 130 131 if runtime.GOOS != "darwin" && clangVersion != nil { 132 // LLVM's continuous mode requires compile-time support on non-macOS 133 // platforms. This support is unstable in Clang 13 and lower, so we 134 // only enable it on 14+. 135 if clangVersion.Compare(semver.MustParse("14.0.0")) >= 0 { 136 cflags = append(cflags, "-mllvm", "-runtime-counter-relocation") 137 } 138 } 139 return cflags 140 }