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 testonly = pw_unit_test_TESTONLY 78 forward_variables_from(invoker, 79 "*", 80 [ 81 "enable_test_if", 82 "visibility", 83 ]) 84 forward_variables_from(invoker, [ "visibility" ]) 85 if (pw_toolchain_OSS_FUZZ_ENABLED) { 86 configs += [ "$dir_pw_fuzzer:libfuzzer_oss_fuzz_config" ] 87 } else { 88 configs += [ "$dir_pw_fuzzer:libfuzzer_config" ] 89 } 90 deps += [ 91 ":$_test_metadata", 92 "$dir_pw_fuzzer:libfuzzer", 93 ] 94 output_dir = _fuzzer_output_dir 95 metadata = { 96 test_barrier = [ ":$_test_metadata" ] 97 } 98 } 99 } 100 101 group(target_name + ".run") { 102 } 103 104 pw_test("${target_name}_test") { 105 deps = [] 106 forward_variables_from(invoker, "*", [ "visibility" ]) 107 forward_variables_from(invoker, [ "visibility" ]) 108 deps += [ "$dir_pw_fuzzer:libfuzzer_test" ] 109 enable_if = !defined(enable_test_if) || enable_test_if 110 } 111} 112 113# Defines a related collection of fuzzers. 114# 115# This template wraps `pw_test_group` to collect a set of libFuzzer-based fuzzer 116# tests. These unit tests do not perform fuzzing. Instead, they execute the fuzz 117# target function with a set of fixed inputs to verify the fuzzer can be built 118# and run. 119# 120# If and only if the current toolchain supports fuzzing, this template will also 121# include the fuzzers themselves. 122# 123# As with `pw_test_group`, targets defined using this template will produce test 124# metadata with a `test_type` of "test_group" and an additional `deps` list 125# describing the tests collected by this target. 126# 127# Args: 128# - fuzzers: List of `pw_fuzzer` targets for each of the fuzzers in the group. 129# 130# - The following args have the same meaning as for `pw_python_action`: 131# group_deps 132# enable_if 133# output_metadata 134template("pw_fuzzer_group") { 135 _with_fuzzers = pw_toolchain_FUZZING_ENABLED && pw_toolchain_SANITIZERS != [] 136 pw_test_group(target_name) { 137 forward_variables_from(invoker, 138 "*", 139 [ 140 "fuzzers", 141 "tests", 142 ]) 143 tests = [] 144 foreach(fuzzer, invoker.fuzzers) { 145 if (_with_fuzzers) { 146 tests += [ fuzzer ] 147 } 148 tests += [ fuzzer + "_test" ] 149 } 150 } 151} 152