# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import("//build/config/chrome_build.gni") import("//build/config/chromecast_build.gni") import("//build/config/sanitizers/sanitizers.gni") import("//build/toolchain/toolchain.gni") # Contains the dependencies needed for sanitizers to link into executables and # shared_libraries. Unconditionally depend upon this target as it is empty if # |is_asan|, |is_lsan|, |is_tsan|, |is_msan| and |use_custom_libcxx| are false. group("deps") { deps = [ ":deps_no_options", ] if (using_sanitizer) { public_configs = [ ":sanitizer_options_link_helper", # Even when a target removes default_sanitizer_flags, it may be depending # on a library that did not remove default_sanitizer_flags. Thus, we need # to add the ldflags here as well as in default_sanitizer_flags. ":default_sanitizer_ldflags", ] deps += [ ":options_sources" ] } } group("deps_no_options") { if (using_sanitizer) { public_configs = [ # Even when a target removes default_sanitizer_flags, it may be depending # on a library that did not remove default_sanitizer_flags. Thus, we need # to add the ldflags here as well as in default_sanitizer_flags. ":default_sanitizer_ldflags", ] deps = [] if (use_prebuilt_instrumented_libraries) { deps += [ "//third_party/instrumented_libraries:deps" ] } if (use_custom_libcxx) { deps += [ "//buildtools/third_party/libc++:libcxx_proxy" ] } if (is_mac) { data_deps = [ ":copy_asan_runtime", ] } } } if (is_mac) { copy("copy_asan_runtime") { sources = [ "//third_party/llvm-build/Release+Asserts/lib/clang/$clang_version/lib/darwin/libclang_rt.asan_osx_dynamic.dylib", ] outputs = [ "$root_out_dir/{{source_file_part}}", ] } } config("sanitizer_options_link_helper") { if (is_mac) { ldflags = [ "-Wl,-U,_sanitizer_options_link_helper" ] } else if (!is_win) { ldflags = [ "-Wl,-u_sanitizer_options_link_helper" ] } } static_library("options_sources") { # This is a static_library instead of a source_set, as it shouldn't be # unconditionally linked into targets. visibility = [ ":deps", "//:gn_visibility", ] sources = [ "//build/sanitizers/sanitizer_options.cc", ] # Don't compile this target with any sanitizer code. It can be called from # the sanitizer runtimes, so instrumenting these functions could cause # recursive calls into the runtime if there is an error. configs -= [ "//build/config/sanitizers:default_sanitizer_flags" ] if (is_asan) { sources += [ "//build/sanitizers/asan_suppressions.cc" ] } if (is_lsan) { sources += [ "//build/sanitizers/lsan_suppressions.cc" ] } if (is_tsan) { sources += [ "//build/sanitizers/tsan_suppressions.cc" ] } } # Applies linker flags necessary when either :deps or :default_sanitizer_flags # are used. config("default_sanitizer_ldflags") { visibility = [ ":default_sanitizer_flags", ":deps", ] if (is_posix) { ldflags = [] if (is_asan) { ldflags += [ "-fsanitize=address" ] } if (is_lsan) { ldflags += [ "-fsanitize=leak" ] } if (is_tsan) { ldflags += [ "-fsanitize=thread" ] } if (is_msan) { ldflags += [ "-fsanitize=memory" ] } if (is_ubsan || is_ubsan_security) { ldflags += [ "-fsanitize=undefined" ] } if (is_ubsan_vptr) { ldflags += [ "-fsanitize=vptr" ] } if (is_cfi && !is_nacl) { ldflags += [ "-fsanitize=cfi-vcall", "-fsanitize=cfi-derived-cast", "-fsanitize=cfi-unrelated-cast", ] if (use_cfi_diag) { ldflags += [ "-fno-sanitize-trap=cfi", "-fsanitize-recover=cfi", ] } } } } config("common_sanitizer_flags") { cflags = [] cflags_cc = [] # Sanitizers need line table info for stack traces. They don't need type info # or variable info, so we can leave that out to speed up the build. if (using_sanitizer) { assert(is_clang, "sanitizers only supported with clang") cflags += [ "-gline-tables-only" ] } # Common options for AddressSanitizer, LeakSanitizer, ThreadSanitizer, # MemorySanitizer and non-official CFI builds. if (using_sanitizer || (is_cfi && !is_official_build)) { if (is_posix) { cflags += [ "-fno-omit-frame-pointer" ] } else { cflags += [ "/Oy-" ] } } if (use_custom_libcxx) { prefix = "//buildtools/third_party" include = "trunk/include" cflags_cc += [ "-nostdinc++", "-isystem" + rebase_path("$prefix/libc++/$include", root_build_dir), "-isystem" + rebase_path("$prefix/libc++abi/$include", root_build_dir), ] } } config("asan_flags") { cflags = [] if (is_asan) { cflags += [ "-fsanitize=address" ] if (is_win) { cflags += [ "-fsanitize-blacklist=" + rebase_path("//tools/memory/asan/blacklist_win.txt", root_build_dir) ] } else { # TODO(rnk): Remove this as discussed in http://crbug.com/427202. cflags += [ "-fsanitize-blacklist=" + rebase_path("//tools/memory/asan/blacklist.txt", root_build_dir) ] } if (is_android) { # Android build relies on -Wl,--gc-sections removing unreachable code. # ASan instrumentation for globals inhibits this and results in a # library with unresolvable relocations. # TODO(eugenis): find a way to reenable this. cflags += [ "-mllvm", "-asan-globals=0", ] } else if (is_mac) { # http://crbug.com/352073 cflags += [ "-mllvm", "-asan-globals=0", ] # TODO(GYP): deal with mac_bundles. } else if (is_win) { assert(target_cpu == "x86", "WinASan is 32-bit only currently") if (is_component_build) { libs = [ "clang_rt.asan_dynamic-i386.lib", "clang_rt.asan_dynamic_runtime_thunk-i386.lib", ] } else { # TODO(rnk): DLLs in the non-component build should link against # clang_rt.asan_dll_thunk-i386.lib instead. libs = [ "clang_rt.asan-i386.lib" ] } } } } config("cfi_flags") { cflags = [] if (is_cfi && !is_nacl) { cfi_blacklist_path = rebase_path("//tools/cfi/blacklist.txt", root_build_dir) cflags += [ "-fsanitize=cfi-vcall", "-fsanitize=cfi-derived-cast", "-fsanitize=cfi-unrelated-cast", "-fsanitize-blacklist=$cfi_blacklist_path", ] if (use_cfi_diag) { cflags += [ "-fno-sanitize-trap=cfi", "-fsanitize-recover=cfi", "-fno-inline-functions", "-fno-inline", "-fno-omit-frame-pointer", "-O1", ] } else { defines = [ "CFI_ENFORCEMENT" ] } } } config("coverage_flags") { cflags = [] if (use_sanitizer_coverage) { cflags += [ "-fsanitize-coverage=$sanitizer_coverage_flags", "-mllvm", "-sanitizer-coverage-prune-blocks=1", ] if (target_cpu == "arm") { # http://crbug.com/517105 cflags += [ "-mllvm", "-sanitizer-coverage-block-threshold=0", ] } defines = [ "SANITIZER_COVERAGE" ] } } config("lsan_flags") { if (is_lsan) { cflags = [ "-fsanitize=leak" ] } } config("msan_flags") { if (is_msan) { assert(is_linux, "msan only supported on linux x86_64") msan_blacklist_path = rebase_path("//tools/msan/blacklist.txt", root_build_dir) cflags = [ "-fsanitize=memory", "-fsanitize-memory-track-origins=$msan_track_origins", "-fsanitize-blacklist=$msan_blacklist_path", ] } } config("tsan_flags") { if (is_tsan) { assert(is_linux, "tsan only supported on linux x86_64") tsan_blacklist_path = rebase_path("//tools/memory/tsan_v2/ignores.txt", root_build_dir) cflags = [ "-fsanitize=thread", "-fsanitize-blacklist=$tsan_blacklist_path", ] } } config("ubsan_flags") { cflags = [] if (is_ubsan) { ubsan_blacklist_path = rebase_path("//tools/ubsan/blacklist.txt", root_build_dir) cflags += [ # Yasm dies with an "Illegal instruction" error when bounds checking is # enabled. See http://crbug.com/489901 # "-fsanitize=bounds", "-fsanitize=float-divide-by-zero", "-fsanitize=integer-divide-by-zero", "-fsanitize=null", "-fsanitize=object-size", "-fsanitize=return", "-fsanitize=returns-nonnull-attribute", "-fsanitize=shift-exponent", "-fsanitize=signed-integer-overflow", "-fsanitize=unreachable", "-fsanitize=vla-bound", "-fsanitize-blacklist=$ubsan_blacklist_path", ] # Chromecast ubsan builds fail to compile with these # experimental flags, so only add them to non-chromecast ubsan builds. if (!is_chromecast) { cflags += [ # Employ the experimental PBQP register allocator to avoid slow # compilation on files with too many basic blocks. # See http://crbug.com/426271. "-mllvm", "-regalloc=pbqp", # Speculatively use coalescing to slightly improve the code generated # by PBQP regallocator. May increase compile time. "-mllvm", "-pbqp-coalescing", ] } } } config("ubsan_no_recover") { if (is_ubsan_no_recover) { cflags = [ "-fno-sanitize-recover=undefined" ] } } config("ubsan_security_flags") { if (is_ubsan_security) { ubsan_blacklist_path = rebase_path("//tools/ubsan/blacklist.txt", root_build_dir) cflags = [ "-fsanitize=signed-integer-overflow,shift", "-fsanitize-blacklist=$ubsan_blacklist_path", ] } } config("ubsan_vptr_flags") { if (is_ubsan_vptr) { ubsan_vptr_blacklist_path = rebase_path("//tools/ubsan/vptr_blacklist.txt", root_build_dir) cflags = [ "-fsanitize=vptr", "-fsanitize-blacklist=$ubsan_vptr_blacklist_path", ] } } all_sanitizer_configs = [ ":common_sanitizer_flags", ":coverage_flags", ":default_sanitizer_ldflags", ":asan_flags", ":cfi_flags", ":lsan_flags", ":msan_flags", ":tsan_flags", ":ubsan_flags", ":ubsan_no_recover", ":ubsan_security_flags", ":ubsan_vptr_flags", ] # This config is applied by default to all targets. It sets the compiler flags # for sanitizer usage, or, if no sanitizer is set, does nothing. # # This needs to be in a separate config so that targets can opt out of # sanitizers (by removing the config) if they desire. Even if a target # removes this config, executables & shared libraries should still depend on # :deps if any of their dependencies have not opted out of sanitizers. # Keep this list in sync with default_sanitizer_flags_but_ubsan_vptr. config("default_sanitizer_flags") { configs = all_sanitizer_configs } # This config is equivalent to default_sanitizer_flags, but excludes ubsan_vptr. # This allows to selectively disable ubsan_vptr, when needed. In particular, # if some third_party code is required to be compiled without rtti, which # is a requirement for ubsan_vptr. config("default_sanitizer_flags_but_ubsan_vptr") { configs = all_sanitizer_configs - [ ":ubsan_vptr_flags" ] } config("default_sanitizer_flags_but_coverage") { configs = all_sanitizer_configs - [ ":coverage_flags" ] }