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

# Individual libfuzzer tests that didn't find their home yet.

import("//build/config/features.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//third_party/protobuf/proto_library.gni")
import("//v8/gni/v8.gni")

# root BUILD depends on this target. Needed for package discovery
group("fuzzers") {
}

fuzzer_test("string_compare_fuzzer") {
  sources = [ "string_compare_fuzzer.cc" ]
  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]

  # TODO(crbug.com/509668952): Remove this when smoke tests support FuzzTest.
  is_fuzztest_compatible = false
}

test("string_compare_fuzztest_fuzzer") {
  sources = [ "string_compare_fuzztest_fuzzer.cc" ]
  fuzztests = [ "TestFuzzer.StringCompare" ]
  deps = [ "//third_party/fuzztest:fuzztest_gtest_main" ]
  configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
}

if (use_centipede) {
  # Manually wrap the LLVM-style fuzzer to use FUZZ_TEST.
  test("string_compare_fuzztest_wrapper_fuzzer") {
    sources = [ "string_compare_fuzzer.cc" ]
    fuzztests = [ "LLVMFuzzer.TestOneInput" ]
    deps = [ "//third_party/fuzztest:llvm_wrapper" ]
    configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
  }
}

test("string_compare_seeded_fuzztest_fuzzer") {
  sources = [ "string_compare_seeded_fuzztest_fuzzer.cc" ]
  fuzztests = [ "TestFuzzer.StringCompareWithSeeds" ]
  deps = [ "//third_party/fuzztest:fuzztest_gtest_main" ]
  configs += [ "//testing/libfuzzer:no_clusterfuzz" ]
}

fuzzer_test("string_compare_proto_fuzzer") {
  sources = [ "string_compare_proto_fuzzer.cc" ]
  deps = [
    "//testing/libfuzzer/proto:string_compare_proto",
    "//third_party/libprotobuf-mutator",
  ]
  additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]

  # TODO(crbug.com/505034799): Migrate to FUZZ_TEST.
  is_fuzztest_compatible = false
}

fuzzer_test("snappy_compress_fuzzer") {
  sources = [ "snappy_compress_fuzzer.cc" ]
  deps = [ "//third_party/snappy" ]
  seed_corpus = "//third_party/snappy/src/testdata"
}

fuzzer_test("snappy_uncompress_fuzzer") {
  sources = [ "snappy_uncompress_fuzzer.cc" ]
  deps = [ "//third_party/snappy" ]
  seed_corpus = "//third_party/snappy/src/testdata"
}

fuzzer_test("template_url_parser_fuzzer") {
  sources = [ "template_url_parser_fuzzer.cc" ]
  deps = [
    "//base",
    "//base:i18n",
    "//components/search_engines",
    "//mojo/core/embedder",
    "//services/data_decoder/public/cpp",
    "//services/data_decoder/public/cpp:test_support",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
    "//third_party/libxml",
  ]
  dict = "//third_party/libxml/fuzz/xml.dict"
  libfuzzer_options = [ "max_len=4096" ]
}

fuzzer_test("url_parse_proto_fuzzer") {
  sources = [ "url_parse_proto_fuzzer.cc" ]
  deps = [
    "//base",
    "//base:i18n",
    "//testing/libfuzzer/proto:url_proto",
    "//third_party/libprotobuf-mutator",
    "//url",
  ]

  # TODO(crbug.com/505034799): Migrate to FUZZ_TEST.
  is_fuzztest_compatible = false
}

fuzzer_test("libsrtp_fuzzer") {
  sources = [ "libsrtp_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
    "//third_party/libsrtp",
  ]
  libfuzzer_options = [ "max_len=1500" ]
}

libpng_seed_corpuses = [
  "//components/test/data/viz",
  "//third_party/blink/web_tests/images/png-suite/samples",
  "//third_party/blink/web_tests/images/resources/pngfuzz",
]

fuzzer_test("gfx_png_image_fuzzer") {
  sources = [ "gfx_png_image_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
    "//ui/base",
    "//ui/gfx",
  ]
  dict = "dicts/png.dict"
  seed_corpuses = libpng_seed_corpuses
}

fuzzer_test("libxml_xml_read_memory_fuzzer") {
  sources = [ "libxml_xml_read_memory_fuzzer.cc" ]
  deps = [ "//third_party/libxml" ]
  dict = "//third_party/libxml/fuzz/xml.dict"
  seed_corpus = "//third_party/libxml/fuzz/seed_corpus"
}

fuzzer_test("libpng_progressive_read_fuzzer") {
  sources = [ "libpng_read_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
    "//third_party/libpng:libpng_for_testonly",
  ]
  dict = "dicts/png.dict"
  seed_corpuses = libpng_seed_corpuses
}

template("v8_fuzzer") {
  if (defined(invoker.v8_dep)) {
    _deps = [ "//v8:${invoker.v8_dep}" ]
  } else {
    _deps = [ "//v8:${target_name}" ]
  }

  fuzzer_test("v8_${target_name}") {
    forward_variables_from(invoker,
                           "*",
                           [
                             "v8_dep",
                             "max_len",
                           ])

    sources = []
    deps = _deps
    if (defined(invoker.max_len)) {
      if (!defined(libfuzzer_options)) {
        libfuzzer_options = []
      }
      libfuzzer_options += [ "max_len=${invoker.max_len}" ]
    }

    asan_options = [
      "allow_user_segv_handler=1",
      "handle_sigtrap=1",
    ]
    msan_options = [ "handle_sigtrap=1" ]
    ubsan_options = [
      "handle_sigtrap=1",
      "handle_segv=1",
    ]
  }
}

v8_fuzzer("script_parser_fuzzer") {
  v8_dep = "parser_fuzzer"
  dict = "dicts/generated/javascript.dict"
  seed_corpus = "//v8/test/mjsunit/regress/"
  libfuzzer_options = [ "only_ascii=1" ]
}

v8_inspector_fuzzer_corpus_dir = "$target_gen_dir/v8_inspector_fuzzer_corpus"

action("generate_v8_inspector_fuzzer_corpus") {
  script = "generate_v8_inspector_fuzzer_corpus.py"
  sources = [ "generate_v8_inspector_fuzzer_corpus.py" ]
  args = [
    rebase_path("//v8/test/inspector/", root_build_dir),
    rebase_path(v8_inspector_fuzzer_corpus_dir, root_build_dir),
  ]
  outputs = [ v8_inspector_fuzzer_corpus_dir ]
}

v8_fuzzer("inspector_fuzzer") {
  dict = "dicts/generated/javascript.dict"
  seed_corpus = v8_inspector_fuzzer_corpus_dir
  seed_corpus_deps = [ ":generate_v8_inspector_fuzzer_corpus" ]

  # The fuzzer is able to handle any input, but since the input is interpreted
  # as JS code, restricting to ascii only will increase fuzzing efficiency.
  libfuzzer_options = [ "only_ascii=1" ]
}

v8_fuzzer("json_parser_fuzzer") {
  v8_dep = "json_fuzzer"
  dict = "dicts/json.dict"
}

v8_fuzzer("regexp_parser_fuzzer") {
  v8_dep = "regexp_fuzzer"
  dict = "dicts/regexp.dict"
  seed_corpus = "//v8/test/fuzzer/regexp/"
  libfuzzer_options = [ "max_len=64" ]
}

if (v8_enable_webassembly) {
  v8_fuzzer("multi_return_fuzzer") {
    # TODO(https://crbug.com/394563978): Remove once experiment ends.
    high_end_job_required = true
    high_end_debug_job_required = true
  }

  v8_fuzzer("wasm_code_fuzzer") {
    max_len = 500

    # TODO(https://crbug.com/394563978): Remove once experiment ends.
    high_end_job_required = true
    high_end_debug_job_required = true
  }

  v8_fuzzer("wasm_module_fuzzer") {
    max_len = 500
    seed_corpus = "//testing/libfuzzer/fuzzers/wasm_corpus/"

    # TODO(https://crbug.com/394563978): Remove once experiment ends.
    high_end_job_required = true
    high_end_debug_job_required = true
  }

  v8_fuzzer("wasm_async_fuzzer") {
    max_len = 500
    seed_corpus = "//testing/libfuzzer/fuzzers/wasm_corpus/"

    # TODO(https://crbug.com/394563978): Remove once experiment ends.
    high_end_job_required = true
    high_end_debug_job_required = true
  }

  v8_fuzzer("wasm_streaming_fuzzer") {
    max_len = 500
    seed_corpus = "//testing/libfuzzer/fuzzers/wasm_corpus/"

    # TODO(https://crbug.com/394563978): Remove once experiment ends.
    high_end_job_required = true
    high_end_debug_job_required = true
  }

  # These fuzzers are not supported in official builds as they depend on
  # functionality in the v8 library that is skipped in official builds for
  # binary size reasons.
  if (!is_official_build) {
    v8_fuzzer("wasm_compile_all_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }

    v8_fuzzer("wasm_compile_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }

    v8_fuzzer("wasm_compile_simd_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }

    v8_fuzzer("wasm_compile_wasmgc_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }

    v8_fuzzer("wasm_compile_revec_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }

    v8_fuzzer("wasm_init_expr_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }

    v8_fuzzer("wasm_deopt_fuzzer") {
      max_len = 500

      # TODO(https://crbug.com/394563978): Remove once experiment ends.
      high_end_job_required = true
      high_end_debug_job_required = true
    }
  }
}

fuzzer_test("convert_woff2ttf_fuzzer") {
  sources = [ "convert_woff2ttf_fuzzer.cc" ]
  deps = [ "//third_party/woff2:woff2_dec" ]
  seed_corpus = "//testing/libfuzzer/fuzzers/woff2_corpus"
  libfuzzer_options = [ "max_len=803500" ]
}

fuzzer_test("flatbuffers_verifier_fuzzer") {
  sources = [ "flatbuffers_verifier_fuzzer.cc" ]
  deps = [
    "//third_party/flatbuffers",
    "//third_party/flatbuffers:flatbuffers_samplebuffer",
  ]
  libfuzzer_options = [ "max_len=1024" ]
  seed_corpus = "//testing/libfuzzer/fuzzers/flatbuffers_corpus"
}

fuzzer_test("skia_path_fuzzer") {
  sources = [
    "skia_path_common.cc",
    "skia_path_common.h",
    "skia_path_fuzzer.cc",
  ]
  deps = [
    "//base",
    "//skia",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
  ]
  libfuzzer_options = [ "max_len=256" ]
  if (is_debug) {
    # Disabled due to crashing on SkASSERT (crbug.com/642750, crbug.com/643275).
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }
}

fuzzer_test("skia_pathop_fuzzer") {
  sources = [
    "skia_path_common.cc",
    "skia_path_common.h",
    "skia_pathop_fuzzer.cc",
  ]
  deps = [
    "//base",
    "//skia",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
  ]
  libfuzzer_options = [ "max_len=512" ]
  if (is_debug) {
    # Disabled due to crashing on SkASSERT (crbug.com/642750, crbug.com/643275).
    additional_configs = [ "//testing/libfuzzer:no_clusterfuzz" ]
  }
}

fuzzer_test("prtime_fuzzer") {
  sources = [ "prtime_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
  ]
  dict = "dicts/prtime.dict"
  libfuzzer_options = [ "max_len=1024" ]
}

fuzzer_test("angle_translator_fuzzer") {
  sources = []
  deps = [ "//third_party/angle:translator_fuzzer" ]
  libfuzzer_options = [ "max_len=1000" ]
  dict = "dicts/webgl-glsl.dict"
}

fuzzer_test("sha1_fuzzer") {
  sources = [ "sha1_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
  ]
}

fuzzer_test("hash_fuzzer") {
  sources = [ "hash_fuzzer.cc" ]
  deps = [
    "//base",
    "//testing/libfuzzer:libfuzzer_base_wrappers",
  ]
}

action("gen_javascript_parser_proto") {
  # Only targets in this file and the top-level visibility target can
  # depend on this.
  visibility = [ ":*" ]

  script = "generate_javascript_parser_proto.py"

  sources = [ "dicts/javascript_parser_proto.dict" ]

  outputs = [
    "$target_gen_dir/javascript_parser.proto",
    "$target_gen_dir/javascript_parser_proto_to_string.cc",
  ]

  args = rebase_path(outputs, root_build_dir) +
         rebase_path(sources, root_build_dir)
}

proto_library("javascript_parser_proto") {
  sources = [ "$target_gen_dir/javascript_parser.proto" ]
  proto_deps = [ ":gen_javascript_parser_proto" ]
  proto_out_dir = ""
}

fuzzer_test("javascript_parser_proto_fuzzer") {
  generated_sources = [ "$target_gen_dir/javascript_parser_proto_to_string.cc" ]
  sources = [
    "javascript_parser_proto_fuzzer.cc",
    "javascript_parser_proto_to_string.h",
  ]
  deps = [
    ":gen_javascript_parser_proto",
    ":javascript_parser_proto",
    "//base",
    "//third_party/libprotobuf-mutator",
    "//v8",
    "//v8:v8_libplatform",
  ]

  # TODO(crbug.com/505034799): Migrate to FUZZ_TEST.
  is_fuzztest_compatible = false
}

fuzzer_test("v8_fully_instrumented_fuzzer") {
  sources = [ "v8_fuzzer.cc" ]
  deps = [
    "//base",
    "//v8",
    "//v8:v8_libplatform",
  ]
  dict = "dicts/generated/javascript.dict"
  asan_options = [
    "allow_user_segv_handler=1",
    "handle_sigtrap=1",
  ]
  msan_options = [ "handle_sigtrap=1" ]
  ubsan_options = [
    "handle_sigtrap=1",
    "handle_segv=1",
  ]
  libfuzzer_options = [ "only_ascii=1" ]
}

fuzzer_test("skia_image_filter_proto_fuzzer") {
  sources = [ "skia_image_filter_proto_fuzzer.cc" ]

  deps = [
    "//base",
    "//base/test:test_support",
    "//skia",
    "//testing/libfuzzer/proto:skia_image_filter_converter",
    "//testing/libfuzzer/proto:skia_image_filter_proto",
    "//third_party/libprotobuf-mutator",
  ]

  # TODO(crbug.com/505034799): Migrate to FUZZ_TEST.
  is_fuzztest_compatible = false
}

# We build the libyuv_scale_fuzzer both for fuzztest
# and libfuzzer, for education/comparison purposes.
# Abstract the common parts:
source_set("libyuv_scale_fuzzer_common") {
  testonly = true
  sources = [
    "libyuv_scale_fuzzer.cc",
    "libyuv_scale_fuzzer.h",
  ]

  deps = [ "//base" ]
  public_deps = [ "//third_party/libyuv" ]
}

# The libfuzzer version (which also works with other compatible
# frameworks, e.g. centipede)
fuzzer_test("libyuv_scale_fuzzer") {
  sources = [ "libyuv_scale_fuzzer_libfuzzer.cc" ]
  deps = [ ":libyuv_scale_fuzzer_common" ]
}

# This is a fuzztest fuzzer, which (for now) means we build this as
# a unit test rather than using a fuzzing gn template such as
# fuzzer_test.
# This executable can be run in four modes:
# modes:
# ./libyuv_scale_fuzzer - runs a small amount of fuzzing as if
#    to fit in with a unit test framework, just to look for
#    egregious bugs
# With the enable_fuzztest_fuzz gn arg:
#   ./libyuv_scale_fuzzer -fuzz=    - fuzzes properly.
# With the use_centipede gn arg:
#   centipede --binary=libyuv_scale_fuzzer - fuzzes using centipede
# With the use_libfuzzer gn arg:
#   ./libyuv_scale_fuzzer - runs in a libfuzzer-compatible way
# Note that right now this is using the plain 'test' template.
# In time, we may choose a different option here.
test("libyuv_scale_fuzztest") {
  sources = [ "libyuv_scale_fuzztest.cc" ]
  fuzztests = [ "ScaleFuzz.ScaleDoesNotCrash" ]

  deps = [
    ":libyuv_scale_fuzzer_common",
    "//third_party/fuzztest:fuzztest_gtest_main",
  ]
}

test("paint_vector_icon_fuzztest") {
  sources = [ "paint_vector_icon_fuzztest.cc" ]
  fuzztests = [ "PaintVectorIconFuzzTest.PaintVectorIcon" ]

  deps = [
    "//base",
    "//skia:skia_switches",
    "//third_party/fuzztest:fuzztest_gtest_main",
    "//ui/gfx",
  ]
}

# Figure why this fuzzer constantly misbehaves on libfuzzer builds.
# See crbug.com/406454922.
if (use_centipede) {
  test("chrome_tint_wgsl_fuzzer") {
    sources = [
      "tint_wgsl_fuzzer.cc",
      "tint_wgsl_fuzzer_grammar.h",
    ]
    fuzztests = [
      "ChromiumTintWgslTest.CanParseProgramWithoutCrashing",
      "ChromiumTintWgslTest.CanConvertWgslToIRWithoutCrashing",
    ]
    fuzztest_additional_args = [ "--stack_limit_kb=512" ]

    deps = [
      "//base",
      "//third_party/dawn/src/tint/cmd/fuzz/wgsl:fuzz",
      "//third_party/dawn/src/tint/lang/wgsl/reader",
      "//third_party/fuzztest:fuzztest_gtest_main",
    ]
  }
}
