Home | History | Annotate | Download | only in sanitizers
      1 # Copyright 2014 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 
      5 import("//build/config/chrome_build.gni")
      6 import("//build/config/chromecast_build.gni")
      7 import("//build/config/sanitizers/sanitizers.gni")
      8 import("//build/toolchain/toolchain.gni")
      9 
     10 # Contains the dependencies needed for sanitizers to link into executables and
     11 # shared_libraries. Unconditionally depend upon this target as it is empty if
     12 # |is_asan|, |is_lsan|, |is_tsan|, |is_msan| and |use_custom_libcxx| are false.
     13 group("deps") {
     14   deps = [
     15     ":deps_no_options",
     16   ]
     17   if (using_sanitizer) {
     18     public_configs = [
     19       ":sanitizer_options_link_helper",
     20 
     21       # Even when a target removes default_sanitizer_flags, it may be depending
     22       # on a library that did not remove default_sanitizer_flags. Thus, we need
     23       # to add the ldflags here as well as in default_sanitizer_flags.
     24       ":default_sanitizer_ldflags",
     25     ]
     26     deps += [ ":options_sources" ]
     27   }
     28 }
     29 
     30 group("deps_no_options") {
     31   if (using_sanitizer) {
     32     public_configs = [
     33       # Even when a target removes default_sanitizer_flags, it may be depending
     34       # on a library that did not remove default_sanitizer_flags. Thus, we need
     35       # to add the ldflags here as well as in default_sanitizer_flags.
     36       ":default_sanitizer_ldflags",
     37     ]
     38     deps = []
     39     if (use_prebuilt_instrumented_libraries) {
     40       deps += [ "//third_party/instrumented_libraries:deps" ]
     41     }
     42     if (use_custom_libcxx) {
     43       deps += [ "//buildtools/third_party/libc++:libcxx_proxy" ]
     44     }
     45     if (is_mac) {
     46       data_deps = [
     47         ":copy_asan_runtime",
     48       ]
     49     }
     50   }
     51 }
     52 
     53 if (is_mac) {
     54   copy("copy_asan_runtime") {
     55     sources = [
     56       "//third_party/llvm-build/Release+Asserts/lib/clang/$clang_version/lib/darwin/libclang_rt.asan_osx_dynamic.dylib",
     57     ]
     58     outputs = [
     59       "$root_out_dir/{{source_file_part}}",
     60     ]
     61   }
     62 }
     63 
     64 config("sanitizer_options_link_helper") {
     65   if (is_mac) {
     66     ldflags = [ "-Wl,-U,_sanitizer_options_link_helper" ]
     67   } else if (!is_win) {
     68     ldflags = [ "-Wl,-u_sanitizer_options_link_helper" ]
     69   }
     70 }
     71 
     72 static_library("options_sources") {
     73   # This is a static_library instead of a source_set, as it shouldn't be
     74   # unconditionally linked into targets.
     75   visibility = [
     76     ":deps",
     77     "//:gn_visibility",
     78   ]
     79   sources = [
     80     "//build/sanitizers/sanitizer_options.cc",
     81   ]
     82 
     83   # Don't compile this target with any sanitizer code. It can be called from
     84   # the sanitizer runtimes, so instrumenting these functions could cause
     85   # recursive calls into the runtime if there is an error.
     86   configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ]
     87 
     88   if (is_asan) {
     89     sources += [ "//build/sanitizers/asan_suppressions.cc" ]
     90   }
     91 
     92   if (is_lsan) {
     93     sources += [ "//build/sanitizers/lsan_suppressions.cc" ]
     94   }
     95 
     96   if (is_tsan) {
     97     sources += [ "//build/sanitizers/tsan_suppressions.cc" ]
     98   }
     99 }
    100 
    101 # Applies linker flags necessary when either :deps or :default_sanitizer_flags
    102 # are used.
    103 config("default_sanitizer_ldflags") {
    104   visibility = [
    105     ":default_sanitizer_flags",
    106     ":deps",
    107   ]
    108 
    109   if (is_posix) {
    110     ldflags = []
    111     if (is_asan) {
    112       ldflags += [ "-fsanitize=address" ]
    113     }
    114     if (is_lsan) {
    115       ldflags += [ "-fsanitize=leak" ]
    116     }
    117     if (is_tsan) {
    118       ldflags += [ "-fsanitize=thread" ]
    119     }
    120     if (is_msan) {
    121       ldflags += [ "-fsanitize=memory" ]
    122     }
    123     if (is_ubsan || is_ubsan_security) {
    124       ldflags += [ "-fsanitize=undefined" ]
    125     }
    126     if (is_ubsan_vptr) {
    127       ldflags += [ "-fsanitize=vptr" ]
    128     }
    129 
    130     if (is_cfi && !is_nacl) {
    131       ldflags += [
    132         "-fsanitize=cfi-vcall",
    133         "-fsanitize=cfi-derived-cast",
    134         "-fsanitize=cfi-unrelated-cast",
    135       ]
    136       if (use_cfi_diag) {
    137         ldflags += [
    138           "-fno-sanitize-trap=cfi",
    139           "-fsanitize-recover=cfi",
    140         ]
    141       }
    142     }
    143   }
    144 }
    145 
    146 config("common_sanitizer_flags") {
    147   cflags = []
    148   cflags_cc = []
    149 
    150   # Sanitizers need line table info for stack traces. They don't need type info
    151   # or variable info, so we can leave that out to speed up the build.
    152   if (using_sanitizer) {
    153     assert(is_clang, "sanitizers only supported with clang")
    154     cflags += [ "-gline-tables-only" ]
    155   }
    156 
    157   # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer,
    158   # MemorySanitizer and non-official CFI builds.
    159   if (using_sanitizer || (is_cfi && !is_official_build)) {
    160     if (is_posix) {
    161       cflags += [ "-fno-omit-frame-pointer" ]
    162     } else {
    163       cflags += [ "/Oy-" ]
    164     }
    165   }
    166 
    167   if (use_custom_libcxx) {
    168     prefix = "//buildtools/third_party"
    169     include = "trunk/include"
    170     cflags_cc += [
    171       "-nostdinc++",
    172       "-isystem" + rebase_path("$prefix/libc++/$include", root_build_dir),
    173       "-isystem" + rebase_path("$prefix/libc++abi/$include", root_build_dir),
    174     ]
    175   }
    176 }
    177 
    178 config("asan_flags") {
    179   cflags = []
    180   if (is_asan) {
    181     cflags += [ "-fsanitize=address" ]
    182     if (is_win) {
    183       cflags += [ "-fsanitize-blacklist=" +
    184                   rebase_path("//tools/memory/asan/blacklist_win.txt",
    185                               root_build_dir) ]
    186     } else {
    187       # TODO(rnk): Remove this as discussed in http://crbug.com/427202.
    188       cflags +=
    189           [ "-fsanitize-blacklist=" +
    190             rebase_path("//tools/memory/asan/blacklist.txt", root_build_dir) ]
    191     }
    192     if (is_android) {
    193       # Android build relies on -Wl,--gc-sections removing unreachable code.
    194       # ASan instrumentation for globals inhibits this and results in a
    195       # library with unresolvable relocations.
    196       # TODO(eugenis): find a way to reenable this.
    197       cflags += [
    198         "-mllvm",
    199         "-asan-globals=0",
    200       ]
    201     } else if (is_mac) {
    202       # http://crbug.com/352073
    203       cflags += [
    204         "-mllvm",
    205         "-asan-globals=0",
    206       ]
    207       # TODO(GYP): deal with mac_bundles.
    208     } else if (is_win) {
    209       assert(target_cpu == "x86", "WinASan is 32-bit only currently")
    210       if (is_component_build) {
    211         libs = [
    212           "clang_rt.asan_dynamic-i386.lib",
    213           "clang_rt.asan_dynamic_runtime_thunk-i386.lib",
    214         ]
    215       } else {
    216         # TODO(rnk): DLLs in the non-component build should link against
    217         # clang_rt.asan_dll_thunk-i386.lib instead.
    218         libs = [ "clang_rt.asan-i386.lib" ]
    219       }
    220     }
    221   }
    222 }
    223 
    224 config("cfi_flags") {
    225   cflags = []
    226   if (is_cfi && !is_nacl) {
    227     cfi_blacklist_path =
    228         rebase_path("//tools/cfi/blacklist.txt", root_build_dir)
    229     cflags += [
    230       "-fsanitize=cfi-vcall",
    231       "-fsanitize=cfi-derived-cast",
    232       "-fsanitize=cfi-unrelated-cast",
    233       "-fsanitize-blacklist=$cfi_blacklist_path",
    234     ]
    235 
    236     if (use_cfi_diag) {
    237       cflags += [
    238         "-fno-sanitize-trap=cfi",
    239         "-fsanitize-recover=cfi",
    240         "-fno-inline-functions",
    241         "-fno-inline",
    242         "-fno-omit-frame-pointer",
    243         "-O1",
    244       ]
    245     } else {
    246       defines = [ "CFI_ENFORCEMENT" ]
    247     }
    248   }
    249 }
    250 
    251 config("coverage_flags") {
    252   cflags = []
    253 
    254   if (use_sanitizer_coverage) {
    255     cflags += [
    256       "-fsanitize-coverage=$sanitizer_coverage_flags",
    257       "-mllvm",
    258       "-sanitizer-coverage-prune-blocks=1",
    259     ]
    260     if (target_cpu == "arm") {
    261       # http://crbug.com/517105
    262       cflags += [
    263         "-mllvm",
    264         "-sanitizer-coverage-block-threshold=0",
    265       ]
    266     }
    267     defines = [ "SANITIZER_COVERAGE" ]
    268   }
    269 }
    270 
    271 config("lsan_flags") {
    272   if (is_lsan) {
    273     cflags = [ "-fsanitize=leak" ]
    274   }
    275 }
    276 
    277 config("msan_flags") {
    278   if (is_msan) {
    279     assert(is_linux, "msan only supported on linux x86_64")
    280     msan_blacklist_path =
    281         rebase_path("//tools/msan/blacklist.txt", root_build_dir)
    282     cflags = [
    283       "-fsanitize=memory",
    284       "-fsanitize-memory-track-origins=$msan_track_origins",
    285       "-fsanitize-blacklist=$msan_blacklist_path",
    286     ]
    287   }
    288 }
    289 
    290 config("tsan_flags") {
    291   if (is_tsan) {
    292     assert(is_linux, "tsan only supported on linux x86_64")
    293     tsan_blacklist_path =
    294         rebase_path("//tools/memory/tsan_v2/ignores.txt", root_build_dir)
    295     cflags = [
    296       "-fsanitize=thread",
    297       "-fsanitize-blacklist=$tsan_blacklist_path",
    298     ]
    299   }
    300 }
    301 
    302 config("ubsan_flags") {
    303   cflags = []
    304   if (is_ubsan) {
    305     ubsan_blacklist_path =
    306         rebase_path("//tools/ubsan/blacklist.txt", root_build_dir)
    307     cflags += [
    308       # Yasm dies with an "Illegal instruction" error when bounds checking is
    309       # enabled. See http://crbug.com/489901
    310       # "-fsanitize=bounds",
    311       "-fsanitize=float-divide-by-zero",
    312       "-fsanitize=integer-divide-by-zero",
    313       "-fsanitize=null",
    314       "-fsanitize=object-size",
    315       "-fsanitize=return",
    316       "-fsanitize=returns-nonnull-attribute",
    317       "-fsanitize=shift-exponent",
    318       "-fsanitize=signed-integer-overflow",
    319       "-fsanitize=unreachable",
    320       "-fsanitize=vla-bound",
    321       "-fsanitize-blacklist=$ubsan_blacklist_path",
    322     ]
    323 
    324     # Chromecast ubsan builds fail to compile with these
    325     # experimental flags, so only add them to non-chromecast ubsan builds.
    326     if (!is_chromecast) {
    327       cflags += [
    328         # Employ the experimental PBQP register allocator to avoid slow
    329         # compilation on files with too many basic blocks.
    330         # See http://crbug.com/426271.
    331         "-mllvm",
    332         "-regalloc=pbqp",
    333 
    334         # Speculatively use coalescing to slightly improve the code generated
    335         # by PBQP regallocator. May increase compile time.
    336         "-mllvm",
    337         "-pbqp-coalescing",
    338       ]
    339     }
    340   }
    341 }
    342 
    343 config("ubsan_no_recover") {
    344   if (is_ubsan_no_recover) {
    345     cflags = [ "-fno-sanitize-recover=undefined" ]
    346   }
    347 }
    348 
    349 config("ubsan_security_flags") {
    350   if (is_ubsan_security) {
    351     ubsan_blacklist_path =
    352         rebase_path("//tools/ubsan/blacklist.txt", root_build_dir)
    353     cflags = [
    354       "-fsanitize=signed-integer-overflow,shift",
    355       "-fsanitize-blacklist=$ubsan_blacklist_path",
    356     ]
    357   }
    358 }
    359 
    360 config("ubsan_vptr_flags") {
    361   if (is_ubsan_vptr) {
    362     ubsan_vptr_blacklist_path =
    363         rebase_path("//tools/ubsan/vptr_blacklist.txt", root_build_dir)
    364     cflags = [
    365       "-fsanitize=vptr",
    366       "-fsanitize-blacklist=$ubsan_vptr_blacklist_path",
    367     ]
    368   }
    369 }
    370 
    371 all_sanitizer_configs = [
    372   ":common_sanitizer_flags",
    373   ":coverage_flags",
    374   ":default_sanitizer_ldflags",
    375   ":asan_flags",
    376   ":cfi_flags",
    377   ":lsan_flags",
    378   ":msan_flags",
    379   ":tsan_flags",
    380   ":ubsan_flags",
    381   ":ubsan_no_recover",
    382   ":ubsan_security_flags",
    383   ":ubsan_vptr_flags",
    384 ]
    385 
    386 # This config is applied by default to all targets. It sets the compiler flags
    387 # for sanitizer usage, or, if no sanitizer is set, does nothing.
    388 #
    389 # This needs to be in a separate config so that targets can opt out of
    390 # sanitizers (by removing the config) if they desire. Even if a target
    391 # removes this config, executables & shared libraries should still depend on
    392 # :deps if any of their dependencies have not opted out of sanitizers.
    393 # Keep this list in sync with default_sanitizer_flags_but_ubsan_vptr.
    394 config("default_sanitizer_flags") {
    395   configs = all_sanitizer_configs
    396 }
    397 
    398 # This config is equivalent to default_sanitizer_flags, but excludes ubsan_vptr.
    399 # This allows to selectively disable ubsan_vptr, when needed. In particular,
    400 # if some third_party code is required to be compiled without rtti, which
    401 # is a requirement for ubsan_vptr.
    402 config("default_sanitizer_flags_but_ubsan_vptr") {
    403   configs = all_sanitizer_configs - [ ":ubsan_vptr_flags" ]
    404 }
    405 
    406 config("default_sanitizer_flags_but_coverage") {
    407   configs = all_sanitizer_configs - [ ":coverage_flags" ]
    408 }
    409