fuzzer_test.gni 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. # Copyright 2015 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. # Defines fuzzer_test.
  5. #
  6. import("//build/config/features.gni")
  7. import("//build/config/sanitizers/sanitizers.gni")
  8. import("//testing/test.gni")
  9. # fuzzer_test is used to define individual libfuzzer tests.
  10. #
  11. # Supported attributes:
  12. # - (required) sources - fuzzer test source files
  13. # - deps - test dependencies
  14. # - libs - Additional libraries to link.
  15. # - frameworks - Apple-only. Additional frameworks to link.
  16. # - additional_configs - additional configs to be used for compilation
  17. # - dict - a dictionary file for the fuzzer.
  18. # - environment_variables - certain whitelisted environment variables for the
  19. # fuzzer (AFL_DRIVER_DONT_DEFER is the only one allowed currently).
  20. # - libfuzzer_options - options for the fuzzer (e.g. -close_fd_mask=N).
  21. # - asan_options - AddressSanitizer options (e.g. allow_user_segv_handler=1).
  22. # - msan_options - MemorySanitizer options.
  23. # - ubsan_options - UndefinedBehaviorSanitizer options.
  24. # - seed_corpus - a directory with seed corpus.
  25. # - seed_corpus_deps - dependencies for generating the seed corpus.
  26. # - grammar_options - defines a grammar used by a grammar based mutator.
  27. #
  28. # If use_libfuzzer gn flag is defined, then proper fuzzer would be build.
  29. # Without use_libfuzzer or use_afl a unit-test style binary would be built on
  30. # linux and the whole target is a no-op otherwise.
  31. #
  32. # The template wraps test() target with appropriate dependencies.
  33. # If any test run-time options are present (dict or libfuzzer_options), then a
  34. # config (.options file) file would be generated or modified in root output
  35. # dir (next to test).
  36. template("fuzzer_test") {
  37. if (!disable_libfuzzer && use_fuzzing_engine) {
  38. assert(defined(invoker.sources), "Need sources in $target_name.")
  39. test_deps = [ "//testing/libfuzzer:libfuzzer_main" ]
  40. test_data_deps = []
  41. if (defined(invoker.deps)) {
  42. test_deps += invoker.deps
  43. }
  44. if (defined(invoker.data_deps)) {
  45. test_data_deps += invoker.data_deps
  46. }
  47. supporting_file_test_deps = []
  48. supporting_file_test_data_deps = []
  49. if (defined(invoker.seed_corpus) || defined(invoker.seed_corpuses)) {
  50. assert(!(defined(invoker.seed_corpus) && defined(invoker.seed_corpuses)),
  51. "Do not use both seed_corpus and seed_corpuses for $target_name.")
  52. out = "$root_build_dir/$target_name" + "_seed_corpus.zip"
  53. seed_corpus_deps = []
  54. if (defined(invoker.seed_corpus_deps)) {
  55. seed_corpus_deps += invoker.seed_corpus_deps
  56. }
  57. action(target_name + "_seed_corpus") {
  58. script = "//testing/libfuzzer/archive_corpus.py"
  59. testonly = true
  60. args = [
  61. "--output",
  62. rebase_path(out, root_build_dir),
  63. ]
  64. if (defined(invoker.seed_corpus)) {
  65. args += [ rebase_path(invoker.seed_corpus, root_build_dir) ]
  66. }
  67. if (defined(invoker.seed_corpuses)) {
  68. foreach(seed_corpus_path, invoker.seed_corpuses) {
  69. args += [ rebase_path(seed_corpus_path, root_build_dir) ]
  70. }
  71. }
  72. outputs = [ out ]
  73. deps = [ "//testing/libfuzzer:seed_corpus" ] + seed_corpus_deps
  74. }
  75. if (archive_seed_corpus) {
  76. supporting_file_test_deps += [ ":" + target_name + "_seed_corpus" ]
  77. }
  78. }
  79. if (defined(invoker.dict) || defined(invoker.libfuzzer_options) ||
  80. defined(invoker.asan_options) || defined(invoker.msan_options) ||
  81. defined(invoker.ubsan_options) ||
  82. defined(invoker.environment_variables) ||
  83. defined(invoker.grammar_options)) {
  84. if (defined(invoker.dict)) {
  85. # Copy dictionary to output.
  86. copy(target_name + "_dict_copy") {
  87. sources = [ invoker.dict ]
  88. outputs = [ "$root_build_dir/" + target_name + ".dict" ]
  89. }
  90. supporting_file_test_deps += [ ":" + target_name + "_dict_copy" ]
  91. }
  92. # Generate .options file.
  93. config_file_name = target_name + ".options"
  94. action(config_file_name) {
  95. script = "//testing/libfuzzer/gen_fuzzer_config.py"
  96. args = [
  97. "--config",
  98. rebase_path("$root_build_dir/" + config_file_name, root_build_dir),
  99. ]
  100. if (defined(invoker.dict)) {
  101. args += [
  102. "--dict",
  103. rebase_path("$root_build_dir/" + invoker.target_name + ".dict",
  104. root_build_dir),
  105. ]
  106. }
  107. if (defined(invoker.libfuzzer_options)) {
  108. args += [ "--libfuzzer_options" ]
  109. args += invoker.libfuzzer_options
  110. }
  111. if (defined(invoker.asan_options)) {
  112. args += [ "--asan_options" ]
  113. args += invoker.asan_options
  114. }
  115. if (defined(invoker.msan_options)) {
  116. args += [ "--msan_options" ]
  117. args += invoker.msan_options
  118. }
  119. if (defined(invoker.ubsan_options)) {
  120. args += [ "--ubsan_options" ]
  121. args += invoker.ubsan_options
  122. }
  123. if (defined(invoker.environment_variables)) {
  124. args += [ "--environment_variables" ]
  125. args += invoker.environment_variables
  126. }
  127. if (defined(invoker.grammar_options)) {
  128. args += [ "--grammar_options" ]
  129. args += invoker.grammar_options
  130. }
  131. outputs = [ "$root_build_dir/$config_file_name" ]
  132. }
  133. supporting_file_test_deps += [ ":" + config_file_name ]
  134. }
  135. if (generate_fuzzer_owners) {
  136. # Generating owners files is slow, only enable when fuzzing engine is
  137. # used.
  138. owners_file_name = target_name + ".owners"
  139. action(owners_file_name) {
  140. script = "//testing/libfuzzer/gen_fuzzer_owners.py"
  141. pool = "//testing/libfuzzer:fuzzer_owners_pool"
  142. args = [
  143. "--owners",
  144. rebase_path("$root_build_dir/" + owners_file_name, root_build_dir),
  145. ]
  146. if (defined(invoker.sources) && invoker.sources != []) {
  147. args += [ "--sources" ] + rebase_path(invoker.sources, "//")
  148. } else if (defined(invoker.deps) && invoker.deps != []) {
  149. _full_deps = []
  150. foreach(_dep, invoker.deps) {
  151. _full_deps += [ get_label_info(_dep, "dir") + ":" +
  152. get_label_info(_dep, "name") ]
  153. }
  154. args += [
  155. "--build-dir",
  156. rebase_path("$root_build_dir/", root_build_dir),
  157. "--deps",
  158. ] + _full_deps
  159. }
  160. outputs = [ "$root_build_dir/$owners_file_name" ]
  161. }
  162. supporting_file_test_data_deps += [ ":" + owners_file_name ]
  163. }
  164. # Copy to executable folder and codesign for catalyst
  165. if (is_ios) {
  166. # iOS only supports fuzzer in catalyst environment.
  167. assert(target_environment == "catalyst")
  168. # Loop over two kinds of deps to codesign these in two |action_foreach|s.
  169. # Use the "test_deps", "test_data_deps" as identifiers in for loop.
  170. foreach(_deps_type_label,
  171. [
  172. "test_deps",
  173. "test_data_deps",
  174. ]) {
  175. _dep_list = []
  176. if (_deps_type_label == "test_deps") {
  177. _dep_list = supporting_file_test_deps
  178. } else {
  179. _dep_list = supporting_file_test_data_deps
  180. }
  181. _files_to_sign = []
  182. foreach(dep, _dep_list) {
  183. _files_to_sign += get_target_outputs(dep)
  184. }
  185. if (_files_to_sign != []) {
  186. _codesign_action_name =
  187. target_name + "_codesign_supporting_files_" + _deps_type_label
  188. action_foreach(_codesign_action_name) {
  189. testonly = true
  190. script = "//build/config/ios/codesign.py"
  191. sources = _files_to_sign
  192. _codesign_output_path =
  193. "${root_build_dir}/codesign/{{source_file_part}}"
  194. outputs = [ _codesign_output_path ]
  195. args = [
  196. "code-sign-file",
  197. "--identity=" + ios_code_signing_identity,
  198. "--output=" + rebase_path(_codesign_output_path, root_build_dir),
  199. "{{source}}",
  200. ]
  201. deps = _dep_list
  202. }
  203. _bundle_data_name = target_name + "_bundle_data_" + _deps_type_label
  204. bundle_data(_bundle_data_name) {
  205. testonly = true
  206. sources = get_target_outputs(":${_codesign_action_name}")
  207. outputs = [ "{{bundle_executable_dir}}/{{source_file_part}}" ]
  208. public_deps = [ ":${_codesign_action_name}" ]
  209. }
  210. if (_deps_type_label == "test_deps") {
  211. test_deps += [ ":${_bundle_data_name}" ]
  212. } else {
  213. test_data_deps += [ ":${_bundle_data_name}" ]
  214. }
  215. }
  216. }
  217. } else {
  218. test_deps += supporting_file_test_deps
  219. test_data_deps += supporting_file_test_data_deps
  220. }
  221. test(target_name) {
  222. forward_variables_from(invoker,
  223. [
  224. "cflags",
  225. "cflags_cc",
  226. "check_includes",
  227. "defines",
  228. "include_dirs",
  229. "sources",
  230. "libs",
  231. "frameworks",
  232. ])
  233. deps = test_deps
  234. data_deps = test_data_deps
  235. if (defined(invoker.additional_configs)) {
  236. configs += invoker.additional_configs
  237. }
  238. configs += [ "//testing/libfuzzer:fuzzer_test_config" ]
  239. # Used by WebRTC to suppress some Clang warnings in their codebase.
  240. if (defined(invoker.suppressed_configs)) {
  241. configs -= invoker.suppressed_configs
  242. }
  243. if (defined(invoker.generated_sources)) {
  244. sources += invoker.generated_sources
  245. }
  246. if (is_ios) {
  247. info_plist =
  248. "//testing/libfuzzer/fuzzer_support_ios/libfuzzer-Info.plist"
  249. }
  250. if (is_mac) {
  251. sources += [ "//testing/libfuzzer/libfuzzer_exports.h" ]
  252. }
  253. }
  254. } else {
  255. # noop on unsupported platforms.
  256. # mark attributes as used.
  257. not_needed(invoker, "*")
  258. group(target_name) {
  259. }
  260. }
  261. }