# Copyright 2015 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# LibFuzzer is a LLVM tool for coverage-guided fuzz testing.
# See http://www.chromium.org/developers/testing/libfuzzer
#
# To enable libfuzzer, 'use_libfuzzer' GN option should be set to true.
# Or equivalent 'use_centipede' options for that engine.

import("//build/buildflag_header.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("//testing/test.gni")

# This file is depended upon from builds that don't include all
# of Chromium, so nothing in here should assume the existence of
# Chromium or Blink. It's OK for subdirectories (e.g. the fuzzers
# or research subdirectories) to have dependencies on other parts
# of Chromium, but not this file.

buildflag_header("buildflags") {
  header = "buildflags.h"
  flags = [
    "ARCHIVE_SEED_CORPUS=$archive_seed_corpus",
    "REGISTER_FUZZTESTS_IN_TEST_SUITES=$register_fuzztests_in_test_suites",
    "USE_CENTIPEDE=$use_centipede",
  ]
}

# This target allows support libraries (not defined via the fuzzer_test
# template) to depend on libfuzzer_exports.h, which is needed for files
# that define LLVMFuzzerInitialize.
source_set("libfuzzer_exports") {
  sources = [ "libfuzzer_exports.h" ]
}

# Temporary target for legacy reasons. Some third party repos explicitly
# refer to libfuzzer_main though they should refer to fuzzer_engine_main
# instead, and so do some infrastructure repos. We should migrate them
# all to point to :fuzzing_engine_main instead.
# TODO: remove this target once they've all migrated.
source_set("libfuzzer_main") {
  deps = [ ":is_a_fuzz_target" ]
  testonly = true
  sources = []
  if (use_libfuzzer) {
    deps += [ "//third_party/libFuzzer:libfuzzer_main" ]
    if (is_ios) {
      deps +=
          [ "//testing/libfuzzer/fuzzer_support_ios:fuzzing_engine_main_ios" ]
    }
  } else if (use_centipede) {
    deps += [ "//third_party/fuzztest:centipede_runner_main" ]
    data_deps = [
      # Centipede based fuzzers require the centipede runner in order to fuzz.
      "//third_party/fuzztest:centipede",
    ]
  } else {
    sources += [ "unittest_main.cc" ]
  }
}

if (fuzzing_engine_supports_custom_main) {
  # Depend on this if you want to use LLVMFuzzerRunDriver from within an
  # existing executable
  group("fuzzing_engine_no_main") {
    testonly = true
    deps = [
      ":fuzzing_engine_no_main_core",
      ":is_a_fuzz_target",
    ]
  }

  group("fuzzing_engine_no_main_core") {
    testonly = true
    if (use_libfuzzer) {
      deps = [ "//third_party/libFuzzer:libfuzzer" ]
    } else if (use_centipede) {
      deps = [ "//third_party/fuzztest:centipede_runner_no_main" ]
      data_deps = [
        # Centipede based fuzzers require the centipede runner in order to fuzz.
        "//third_party/fuzztest:centipede",
      ]
    } else if (use_chromium_fuzzilli) {
      deps = [ "//testing/libfuzzer/fuzzilli:fuzzilli_driver" ]
    }
  }
}

# The currently selected fuzzing engine, providing a main() function.
# Fuzzers should depend upon this.
group("fuzzing_engine_main") {
  deps = [ ":libfuzzer_main" ]
  testonly = true
}

# Any fuzzer using any fuzzing engine. This will be used by infra scripts
# to identify fuzzers which should be built and made available to ClusterFuzz.
group("is_a_fuzz_target") {
  deps = [ ":fuzzing_engine" ]
}

# Named for legacy reasons for compatibility with recipes.
group("fuzzing_engine") {
  visibility = [ ":is_a_fuzz_target" ]
  if (use_clang_coverage) {
    # For purposes of code coverage calculation, fuzzer targets are run through
    # a wrapper script in this directory, which handles corpus retrieval and
    # appropriate parameter passing to run the target in an isolate. This
    # directive makes this script and its dependencies to be included in the
    # target's isolate.
    data = [ "//tools/code_coverage/" ]
  }
}

# A config used by all fuzzer_tests.
config("fuzzer_test_config") {
  if (use_libfuzzer && is_mac) {
    ldflags = [
      "-Wl,-U,_LLVMFuzzerCustomMutator",
      "-Wl,-U,_LLVMFuzzerInitialize",
    ]
  }
}

# Noop config used to tag fuzzer tests excluded from clusterfuzz.
# Libfuzzer build bot uses this to filter out targets while
# building an archive for clusterfuzz.
config("no_clusterfuzz") {
}

# Since most iOS code doesn't compile in other platforms, and not all fuzzers
# compile in iOS, a clusterfuzz job is set up to run only selected iOS fuzzers.
# This is a noop config to tag fuzzer tests to be built for the job. iOS
# Libfuzzer build bot uses this to filter targets while building an archive for
# the job.
config("build_for_ios_clusterfuzz_job") {
}

# noop to tag seed corpus rules.
source_set("seed_corpus") {
}

if (use_fuzzing_engine) {
  pool("fuzzer_owners_pool") {
    depth = 1
  }
}

if (use_fuzztest_wrapper) {
  # A wrapper that knows how to execute a single fuzztest within a binary
  # containing many fuzztests.
  # Unlike fuzztests themselves, this depends on :is_a_fuzz_target
  # so that the build jobs know to build all these.
  source_set("individual_fuzztest_wrapper") {
    sources = [ "//testing/libfuzzer/fuzztest_wrapper.cpp" ]
    deps = [
      ":buildflags",
      ":is_a_fuzz_target",
      "//base",
    ]
  }
}

source_set("fuzztest_init_support") {
  testonly = true
  sources = [
    "fuzztest_init_helper.cc",
    "fuzztest_init_helper.h",
  ]
}

# Contains a static initializer which will arrange for fuzztests to be
# registered. Usually invoked from testing/test.gni
source_set("confirm_fuzztest_init") {
  sources = [ "confirm_fuzztest_init.cc" ]
  testonly = true
  deps = [
    ":buildflags",
    ":fuzztest_init_support",
    "//third_party/fuzztest:init_fuzztest",
  ]

  # TODO(crbug.com/40031409): Fix code that adds exit-time destructors and
  # enable the diagnostic by removing this line.
  configs += [ "//build/config/compiler:no_exit_time_destructors" ]
}

if (build_with_chromium) {
  source_set("libfuzzer_base_wrappers") {
    testonly = true
    public = [ "libfuzzer_base_wrappers.h" ]
    deps = [ "//base:compiler_specific" ]
  }
}
