chromium/third_party/fuzztest/BUILD.gn

# 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.

# This file is a partial translation of
# //third_party/fuzztest/src/centipede/BUILD
# into BUILD.gn format.
#
# It contains support for both:
# - centipede, a way of building and running Chromium's existing fuzzing
#   targets using an out-of-process runner.
# - fuzztest, a way of building new fuzzing targets using simpler macros.

import("//build/config/android/config.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//build_overrides/build.gni")

# Retain full optimization level for the engine parts independent of the
# optimizations set for the fuzz target.
fuzztest_remove_configs = fuzzing_engine_remove_configs +
                          [ "//build/config/compiler:default_optimization" ]
fuzztest_add_configs =
    fuzzing_engine_add_configs + [ "//build/config/compiler:optimize" ]

config("fuzztest_internal_config") {
  cflags = [
    "-Wno-sign-compare",  # https://github.com/google/centipede/issues/487,
    "-Wno-unused-private-field",
    "-Wno-unreachable-code-return",
    "-Wno-unused-but-set-variable",
    "-Wno-shadow",
    "-Wno-unused-const-variable",
    "-Wno-unused-function",
    "-Wno-inconsistent-missing-override",
    "-Wno-unused-lambda-capture",
  ]

  # int_utils.h depends on an SSE 4.2 intrinsic.
  if (current_cpu == "x64") {
    cflags += [ "-msse4.2" ]
  }
  include_dirs = [ "src" ]

  # Riegeli is a library which centipede can use to store data more
  # efficiently. It's not yet available in Chromium, so disable
  # for now.
  defines = [ "CENTIPEDE_DISABLE_RIEGELI" ]
  if (use_centipede) {
    defines += [ "FUZZTEST_USE_CENTIPEDE" ]
  } else if (use_fuzzing_engine && fuzzing_engine_supports_custom_main) {
    defines += [ "FUZZTEST_COMPATIBILITY_MODE" ]
  }
}

if (use_centipede) {
  source_set("centipede_common") {
    testonly = true
    sources = [
      "src/centipede/binary_info.cc",
      "src/centipede/binary_info.h",
      "src/centipede/byte_array_mutator.cc",
      "src/centipede/byte_array_mutator.h",
      "src/centipede/command.cc",
      "src/centipede/control_flow.cc",
      "src/centipede/defs.h",
      "src/centipede/early_exit.cc",
      "src/centipede/early_exit.h",
      "src/centipede/execution_metadata.cc",
      "src/centipede/execution_metadata.h",
      "src/centipede/feature.cc",
      "src/centipede/feature.h",
      "src/centipede/hash.cc",
      "src/centipede/knobs.cc",
      "src/centipede/knobs.h",
      "src/centipede/logging.h",
      "src/centipede/pc_info.cc",
      "src/centipede/pc_info.h",
      "src/centipede/remote_file.cc",
      "src/centipede/remote_file.h",
      "src/centipede/reverse_pc_table.h",
      "src/centipede/runner_cmp_trace.h",
      "src/centipede/runner_request.cc",
      "src/centipede/runner_request.h",
      "src/centipede/runner_result.cc",
      "src/centipede/runner_result.h",
      "src/centipede/shared_memory_blob_sequence.cc",
      "src/centipede/shared_memory_blob_sequence.h",
      "src/centipede/symbol_table.cc",
      "src/centipede/util.cc",
    ]
    deps = [ "//third_party/abseil-cpp:absl_full" ]
    configs += [ ":fuzztest_internal_config" ]
    configs -= fuzztest_remove_configs
    configs += fuzztest_add_configs
  }

  source_set("centipede_runner_no_main") {
    testonly = true
    sources = [
      "src/centipede/runner.cc",
      "src/centipede/runner.h",
      "src/centipede/runner_dl_info.cc",
      "src/centipede/runner_dl_info.h",
      "src/centipede/runner_fork_server.cc",
      "src/centipede/runner_interceptors.cc",
      "src/centipede/runner_interface.h",
      "src/centipede/runner_sancov.cc",
      "src/centipede/runner_sancov_object.cc",
      "src/centipede/runner_sancov_object.h",
      "src/centipede/runner_utils.cc",
      "src/centipede/runner_utils.h",
    ]

    deps = [
      ":centipede_common",
      "//third_party/abseil-cpp:absl_full",
    ]
    configs += [ ":fuzztest_internal_config" ]
    configs -= fuzztest_remove_configs
    configs += fuzztest_add_configs

    # Ensure that the centipede driver executable is also built
    # whenever we build any centipede-based fuzzer
    data_deps = [ ":centipede" ]

    # sancov symbols need to be exported for centipede to work correctly with
    # multi-dso.
    configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
    configs += [ "//build/config/gcc:symbol_visibility_default" ]
  }

  source_set("centipede_runner_main") {
    testonly = true
    deps = [
      ":centipede_runner_no_main",
      "//third_party/abseil-cpp:absl",
    ]
    configs += [ ":fuzztest_internal_config" ]
    sources = [ "src/centipede/runner_main.cc" ]
  }

  # Parts of centipede which are used for the external execution executable,
  # but are also now built into fuzztests themselves so that they no longer
  # depend on an external runner
  source_set("centipede_executable_engine") {
    configs += [ ":fuzztest_internal_config" ]
    configs -= fuzztest_remove_configs
    configs += fuzztest_add_configs
    include_dirs = [ "src" ]
    testonly = true
    public_deps = [ ":centipede_common" ]
    libs = [ "atomic" ]
    deps = [
      ":fuzztest_internal",
      "//third_party/abseil-cpp:absl_full",
      "//third_party/boringssl",
    ]
    sources = [
      "src/centipede/analyze_corpora.cc",
      "src/centipede/blob_file.cc",
      "src/centipede/call_graph.cc",
      "src/centipede/centipede.cc",
      "src/centipede/centipede_callbacks.cc",
      "src/centipede/centipede_default_callbacks.cc",
      "src/centipede/centipede_interface.cc",
      "src/centipede/config_file.cc",
      "src/centipede/config_init.cc",
      "src/centipede/config_util.cc",
      "src/centipede/corpus.cc",
      "src/centipede/corpus_io.cc",
      "src/centipede/coverage.cc",
      "src/centipede/distill.cc",
      "src/centipede/distill.h",
      "src/centipede/environment.cc",
      "src/centipede/feature_set.cc",
      "src/centipede/feature_set.h",
      "src/centipede/fuzztest_mutator.cc",
      "src/centipede/fuzztest_mutator.h",
      "src/centipede/minimize_crash.cc",
      "src/centipede/periodic_action.cc",
      "src/centipede/periodic_action.h",
      "src/centipede/resource_pool.cc",
      "src/centipede/rusage_profiler.cc",
      "src/centipede/rusage_stats.cc",
      "src/centipede/stats.cc",
      "src/centipede/workdir.cc",
      "src/centipede/workdir.h",
    ]
  }

  # The centipede out-of-process runner executable.
  executable("centipede") {
    testonly = true
    configs += [ ":fuzztest_internal_config" ]
    configs -= fuzztest_remove_configs
    configs += fuzztest_add_configs
    deps = [
      ":centipede_executable_engine",
      "//third_party/abseil-cpp:absl_full",
    ]
    sources = [
      "src/centipede/centipede_main.cc",
      "src/centipede/environment_flags.cc",
      "src/centipede/environment_flags.h",
    ]
  }
}

if (use_centipede || enable_fuzztest_fuzz) {
  source_set("centipede_weak_sancov_stubs") {
    sources = [ "src/centipede/weak_sancov_stubs.cc" ]
  }
}

# Parts of fuzztest internals which are safe to include in all sorts
# of test-related code, including other fuzzers.
source_set("fuzztest_internal") {
  if (defined(android_ndk_major_version) && android_ndk_major_version < 28) {
    # Android API level 28+ has posix_spawnp
    defines = [ "FUZZTEST_DISABLE_SUBPROCESS" ]
  }

  sources = [
    "src/fuzztest/domain.h",
    "src/fuzztest/domain_core.h",
    "src/fuzztest/fuzztest.h",
    "src/fuzztest/fuzztest_macros.cc",
    "src/fuzztest/fuzztest_macros.h",
    "src/fuzztest/googletest_fixture_adapter.h",
    "src/fuzztest/internal/any.h",
    "src/fuzztest/internal/centipede_adaptor.h",
    "src/fuzztest/internal/compatibility_mode.h",
    "src/fuzztest/internal/configuration.cc",
    "src/fuzztest/internal/configuration.h",
    "src/fuzztest/internal/corpus_database.cc",
    "src/fuzztest/internal/corpus_database.h",
    "src/fuzztest/internal/coverage.cc",
    "src/fuzztest/internal/coverage.h",
    "src/fuzztest/internal/domains/absl_helpers.h",
    "src/fuzztest/internal/domains/aggregate_of_impl.h",
    "src/fuzztest/internal/domains/arbitrary_impl.h",
    "src/fuzztest/internal/domains/bit_flag_combination_of_impl.h",
    "src/fuzztest/internal/domains/container_mutation_helpers.h",
    "src/fuzztest/internal/domains/container_of_impl.h",
    "src/fuzztest/internal/domains/domain_base.cc",
    "src/fuzztest/internal/domains/domain_base.h",
    "src/fuzztest/internal/domains/element_of_impl.h",
    "src/fuzztest/internal/domains/filter_impl.h",
    "src/fuzztest/internal/domains/flat_map_impl.h",
    "src/fuzztest/internal/domains/in_grammar_impl.cc",
    "src/fuzztest/internal/domains/in_grammar_impl.h",
    "src/fuzztest/internal/domains/in_range_impl.h",
    "src/fuzztest/internal/domains/in_regexp_impl.h",
    "src/fuzztest/internal/domains/map_impl.h",
    "src/fuzztest/internal/domains/one_of_impl.h",
    "src/fuzztest/internal/domains/optional_of_impl.h",
    "src/fuzztest/internal/domains/protobuf_domain_impl.h",
    "src/fuzztest/internal/domains/regexp_dfa.cc",
    "src/fuzztest/internal/domains/regexp_dfa.h",
    "src/fuzztest/internal/domains/serialization_helpers.h",
    "src/fuzztest/internal/domains/smart_pointer_of_impl.h",
    "src/fuzztest/internal/domains/unique_elements_container_of_impl.h",
    "src/fuzztest/internal/domains/value_mutation_helpers.h",
    "src/fuzztest/internal/domains/variant_of_impl.h",
    "src/fuzztest/internal/fixture_driver.cc",
    "src/fuzztest/internal/fixture_driver.h",
    "src/fuzztest/internal/googletest_adaptor.cc",
    "src/fuzztest/internal/googletest_adaptor.h",
    "src/fuzztest/internal/io.cc",
    "src/fuzztest/internal/io.h",
    "src/fuzztest/internal/logging.cc",
    "src/fuzztest/internal/logging.h",
    "src/fuzztest/internal/meta.h",
    "src/fuzztest/internal/registration.h",
    "src/fuzztest/internal/registry.cc",
    "src/fuzztest/internal/registry.h",
    "src/fuzztest/internal/runtime.cc",
    "src/fuzztest/internal/runtime.h",
    "src/fuzztest/internal/seed_seq.cc",
    "src/fuzztest/internal/seed_seq.h",
    "src/fuzztest/internal/serialization.cc",
    "src/fuzztest/internal/serialization.h",
    "src/fuzztest/internal/status.cc",
    "src/fuzztest/internal/status.h",
    "src/fuzztest/internal/subprocess.cc",
    "src/fuzztest/internal/subprocess.h",
    "src/fuzztest/internal/table_of_recent_compares.h",
    "src/fuzztest/internal/type_support.cc",
    "src/fuzztest/internal/type_support.h",
  ]

  testonly = true

  deps = [
    "//testing/gtest",
    "//third_party/abseil-cpp:absl_full",
  ]

  # TODO(https://crbug.com/337736622): Remove this after M129 when V8 moves
  # protobuf back to //third_party/protobuf.
  if (!defined(protobuf_target_prefix)) {
    protobuf_target_prefix = "//third_party/protobuf"
  }

  public_deps = [
    "//third_party/abseil-cpp:absl",

    # For RE2 mutators. It's questionable whether we want to pull this library
    # into every fuzztest target, but this is the approach used in other
    # fuzztest contexts so we'll do the same
    "//third_party/re2",

    # For protobuf mutators
    "$protobuf_target_prefix:protobuf_lite",
  ]

  public_configs = [ ":fuzztest_internal_config" ]
  configs -= fuzztest_remove_configs
  configs += fuzztest_add_configs
}

# Fuzztest support. This allows regular test executables to contain
# a FUZZ_TEST. Such tests/executables should depend directly on this target;
# at this time there's no need to use a special gn template for fuzz tests.
# The resulting executables may be used in a variety of modes:
#  ./my_test     # just runs. The FUZZ_TEST runs for 1 second.
#  ./my_test --fuzz=    # runs fuzzing indefinitely.
#                       # Requires enable_fuzztest_fuzz gn argument.
#  ./my_test --fuzz=    # If use_libfuzzer gn argument is enabled, this
#                       # causes the test to emulate a regular libfuzzer fuzzer.
#  centipede --binary=./mytest  # Allows the binary to be run using centipede
#                               # out of process execution environment.
#                               # Requires use_centipede gn argument.
# Nothing in this target depends upon //testing/libfuzzer:is_a_fuzz_target,
# so dependent binaries won't directly be built by the fuzzing build job.
# However, any uses of the test("...") template which declare that they
# have fuzztests will cause wrapper executables to be built (because they
# will depend upon :is_a_fuzz_target). Such executables will have a data_dep
# on the underlying fuzztest executable, so it will get built.
source_set("fuzztest") {
  deps = [
    "//testing/gtest",
    "//third_party/abseil-cpp:absl_full",
  ]
  if (use_centipede) {
    # If we are building for centipede, we want to make fuzztest executables
    # which can be used as centipede fuzzers.
    sources = [ "src/fuzztest/internal/centipede_adaptor.cc" ]
    deps += [
      ":centipede_executable_engine",
      ":centipede_runner_no_main",
    ]
  } else if (use_fuzzing_engine && fuzzing_engine_supports_custom_main) {
    # Typically, libfuzzer.
    sources = [ "src/fuzztest/internal/compatibility_mode.cc" ]
    deps += [ "//testing/libfuzzer:fuzzing_engine_no_main_core" ]
  }
  public_deps = [ ":fuzztest_internal" ]
  configs -= fuzztest_remove_configs
  configs += fuzztest_add_configs + [ ":fuzztest_internal_config" ]
  testonly = true
}

# Depend on this if you're a test runner executable (or similar)
# with its own main() but you need to call InitFuzzTest.
source_set("init_fuzztest") {
  sources = [
    "src/fuzztest/init_fuzztest.cc",
    "src/fuzztest/init_fuzztest.h",
  ]
  deps = [
    "//testing/gtest",
    "//third_party/abseil-cpp:absl_full",
  ]
  public_deps = [ ":fuzztest_internal" ]
  configs -= fuzztest_remove_configs
  configs += fuzztest_add_configs + [ ":fuzztest_internal_config" ]
  testonly = true
}

# Depend upon this if you need a main() function
source_set("fuzztest_gtest_main") {
  deps = [
    "//testing/gtest",
    "//third_party/abseil-cpp:absl_full",
  ]
  sources = [ "src/fuzztest/fuzztest_gtest_main.cc" ]
  public_deps = [
    ":init_fuzztest",
    "//testing/gtest",
  ]
  if (use_centipede) {
    data_deps = [ ":centipede" ]
  }
  testonly = true
}