blob: efbccad80678ceba36bb186311e45c522b0100bd [file] [log] [blame]
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
# This template allows creation of a fuzzer which has access to all the
# functionality of a browser_test, including a full GUI instance of Chromium.
# See in_process_fuzzer.h.
#
# It accepts all the same arguments as //testing/libfuzzer/fuzzer_test.gni's
# fuzzer_test template.
template("in_process_fuzzer") {
if (fuzzing_engine_supports_custom_main) {
fuzzer_test(target_name) {
deps = [ "//chrome/test/fuzzing:in_process_fuzzer_runner" ]
if (defined(invoker.deps)) {
deps += invoker.deps
}
forward_variables_from(invoker,
"*",
[
"deps",
"exclude_main",
"asan_options",
])
# As these are full browser tests, we have crashpad running,
# and we can't intercept signals that crashpad needs.
sanitizer_options = [
"allow_user_segv_handler=1",
"handle_sigtrap=1",
"handle_abort=1",
"handle_segv=1",
"handle_sigbus=1",
"handle_sigfpe=1",
"handle_sigill=1",
"handle_sigtrap=1",
]
asan_options = [
# Browser tests store arbitrary data in globals; leak
# detection will come up with lots of false positives.
"detect_leaks=0",
]
asan_options += sanitizer_options
ubsan_options = sanitizer_options
msan_options = sanitizer_options
# Again, these are full browser tests, so it needs a fairly high memory
# limit so that it runs correctly.
libfuzzer_options = [
"rss_limit_mb=8192",
# We can't allow libfuzzer to fork because these fuzzers may have
# pre-existing threads. See crbug.com/325928325
"fork=0",
]
centipede_options = [
# Provide plenty of capacity for test cases to flow between centipede
# and the fuzz target.
"shmem_size_mb=4096",
# Browser tests are big
"address_space_limit_mb=0",
# For testing. Those fuzzers are extremely slow on ClusterFuzz, and
# using this option doesn't help.
"fork_server=0",
"rss_limit_mb=8192",
# This value is the one used by CF for Centipede fuzzers.
# Default computed timeout per batch is ridiculously low (1127, which
# means ~1.1 sec per input average) for those fuzzers.
"timeout_per_batch=8400",
]
if (defined(invoker.asan_options)) {
asan_options += invoker.asan_options
}
if (defined(invoker.libfuzzer_options)) {
libfuzzer_options += invoker.libfuzzer_options
}
if (defined(invoker.centipede_options)) {
centipede_options += invoker.centipede_options
}
exclude_main = true
}
} else {
# noop if the fuzzer harness always provides its own main
not_needed(invoker, "*")
group(target_name) {
}
}
}
# This template is a proto-based version of the in_process_fuzzer template.
#
# This rule copies the proto-relevant bits from the mojolpm_fuzzer_test
# template (//mojo/public/tools/fuzzers/mojolpm.gni)
#
# Parameters:
# sources
# List of source .cc files to compile.
#
# deps
# List of dependencies to compile this target.
#
# proto_source
# Single source .proto file defining the structure of a testcase.
#
# proto_deps
# List of additional dependencies for compiling proto_source.
#
# testcase_proto_kind (optional, required if seed_corpus_sources provided)
# Name of proto message type representing a testcase.
#
# seed_corpus_sources (optional)
# List of source .textproto files used to build a seed corpus.
template("in_process_proto_fuzzer") {
if (fuzzing_engine_supports_custom_main) {
assert(defined(invoker.sources) && defined(invoker.proto_source),
"\"sources\" and \"proto_source\" must be defined for $target_name")
assert(
!defined(invoker.seed_corpus_sources) ||
defined(invoker.testcase_proto_kind),
"\"testcase_proto_kind\" must be defined for $target_name since \"seed_corpus_sources\" is defined.")
proto_target_name = "${target_name}_proto"
proto_library(proto_target_name) {
# Work relative to src (//) instead of (by default) the BUILD file.
proto_in_dir = "//"
sources = [ invoker.proto_source ]
generate_python = false
proto_deps = []
import_dirs = [ root_gen_dir ]
link_deps = []
if (defined(invoker.proto_deps)) {
proto_deps += invoker.proto_deps
link_deps += invoker.proto_deps
}
testonly = true
}
if (defined(invoker.seed_corpus_sources)) {
protoc_convert_target_name = "${target_name}_protoc_convert"
seed_corpus_path = "${target_gen_dir}/${target_name}_seed_corpus"
protoc_convert(protoc_convert_target_name) {
sources = invoker.seed_corpus_sources
inputs = [ invoker.proto_source ]
output_pattern = "${seed_corpus_path}/{{source_name_part}}.binarypb"
args = [
"--encode=${invoker.testcase_proto_kind}",
"-I",
rebase_path(root_gen_dir),
"-I",
rebase_path("//"),
rebase_path(inputs[0]),
]
deps = []
if (defined(invoker.proto_deps)) {
deps += invoker.proto_deps
}
testonly = true
}
}
in_process_fuzzer(target_name) {
sources = invoker.sources
deps = [
":${proto_target_name}",
"//chrome/test/fuzzing:in_process_proto_fuzzer_runner",
"//third_party/libprotobuf-mutator",
]
if (defined(invoker.deps)) {
deps += invoker.deps
}
if (defined(invoker.seed_corpus_sources)) {
seed_corpus = seed_corpus_path
seed_corpus_deps = [ ":${protoc_convert_target_name}" ]
}
}
} else {
# noop if the fuzzer harness always provides its own main
not_needed(invoker, "*")
group(target_name) {
}
}
}