1# Copyright 2020 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14 15import("//build_overrides/pigweed.gni") 16 17import("$dir_pw_build/error.gni") 18import("$dir_pw_build/test_info.gni") 19import("$dir_pw_toolchain/host_clang/toolchains.gni") 20import("$dir_pw_unit_test/test.gni") 21 22# Creates a libFuzzer-based fuzzer executable target and unit test 23# 24# This will link `sources` and `deps` with the libFuzzer compiler runtime. The 25# `sources` and `deps` should include a definition of the standard LLVM fuzz 26# target function, `LLVMFuzzerTestOneInput`. For more details, see: 27# //pw_fuzzer/docs.rst 28# https://llvm.org/docs/LibFuzzer.html 29# 30# Additionally, this creates a unit test that does not generate fuzzer inputs 31# and simply executes the fuzz target function with fixed inputs. This is useful 32# for verifying the fuzz target function compiles, links, and runs even when not 33# using a fuzzing-capable host or toolchain. 34# 35# Args: 36# - enable_test_if: (optional) Passed as `enable_if` to the unit test. 37# - All of the `pw_executable` args are accepted. 38template("pw_fuzzer") { 39 if (!pw_toolchain_FUZZING_ENABLED) { 40 pw_error(target_name) { 41 message_lines = [ "Toolchain does not enable fuzzing." ] 42 } 43 not_needed(invoker, "*") 44 } else if (pw_toolchain_SANITIZERS == []) { 45 pw_error(target_name) { 46 message_lines = [ "No sanitizer runtime set." ] 47 } 48 not_needed(invoker, "*") 49 } else { 50 # Metadata for this test when used as part of a pw_test_group target. 51 _fuzzer_target_name = target_name 52 _fuzzer_output_dir = "${target_out_dir}/bin" 53 if (defined(invoker.output_dir)) { 54 _fuzzer_output_dir = invoker.output_dir 55 } 56 57 _tags = [ "libfuzzer" ] 58 if (defined(invoker.tags)) { 59 _tags += invoker.tags 60 } 61 62 _test_metadata = "${target_name}.metadata" 63 _extra_metadata = { 64 forward_variables_from(invoker, [ "extra_metadata" ]) 65 test_directory = rebase_path(_fuzzer_output_dir, root_build_dir) 66 } 67 pw_test_info(_test_metadata) { 68 test_type = "fuzz_test" 69 test_name = _fuzzer_target_name 70 tags = _tags 71 extra_metadata = _extra_metadata 72 } 73 74 pw_executable(target_name) { 75 configs = [] 76 deps = [] 77 forward_variables_from(invoker, 78 "*", 79 [ 80 "enable_test_if", 81 "visibility", 82 ]) 83 forward_variables_from(invoker, [ "visibility" ]) 84 if (pw_toolchain_OSS_FUZZ_ENABLED) { 85 configs += [ "$dir_pw_fuzzer:libfuzzer_oss_fuzz_config" ] 86 } else { 87 configs += [ "$dir_pw_fuzzer:libfuzzer_config" ] 88 } 89 deps += [ 90 ":$_test_metadata", 91 "$dir_pw_fuzzer:libfuzzer", 92 ] 93 output_dir = _fuzzer_output_dir 94 metadata = { 95 test_barrier = [ ":$_test_metadata" ] 96 } 97 } 98 } 99 100 group(target_name + ".run") { 101 } 102 103 pw_test("${target_name}_test") { 104 deps = [] 105 forward_variables_from(invoker, "*", [ "visibility" ]) 106 forward_variables_from(invoker, [ "visibility" ]) 107 deps += [ "$dir_pw_fuzzer:libfuzzer_test" ] 108 enable_if = !defined(enable_test_if) || enable_test_if 109 } 110} 111 112# Defines a related collection of fuzzers. 113# 114# This template wraps `pw_test_group` to collect a set of libFuzzer-based fuzzer 115# tests. These unit tests do not perform fuzzing. Instead, they execute the fuzz 116# target function with a set of fixed inputs to verify the fuzzer can be built 117# and run. 118# 119# If and only if the current toolchain supports fuzzing, this template will also 120# include the fuzzers themselves. 121# 122# As with `pw_test_group`, targets defined using this template will produce test 123# metadata with a `test_type` of "test_group" and an additional `deps` list 124# describing the tests collected by this target. 125# 126# Args: 127# - fuzzers: List of `pw_fuzzer` targets for each of the fuzzers in the group. 128# 129# - The following args have the same meaning as for `pw_python_action`: 130# group_deps 131# enable_if 132# output_metadata 133template("pw_fuzzer_group") { 134 _with_fuzzers = pw_toolchain_FUZZING_ENABLED && pw_toolchain_SANITIZERS != [] 135 pw_test_group(target_name) { 136 forward_variables_from(invoker, 137 "*", 138 [ 139 "fuzzers", 140 "tests", 141 ]) 142 tests = [] 143 foreach(fuzzer, invoker.fuzzers) { 144 if (_with_fuzzers) { 145 tests += [ fuzzer ] 146 } 147 tests += [ fuzzer + "_test" ] 148 } 149 } 150} 151