From a3cfaf458ad650f3fbb7e375a88ad9cfba3a118d Mon Sep 17 00:00:00 2001 From: Andrey Astafyev Date: Sat, 12 Jun 2021 14:14:01 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A4=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=B8=D0=BD=D0=B0=D0=BC=D0=B8=D1=87=D0=B5=D1=81=D0=BA?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=82=D0=B5=D1=81=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BA=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitmodules | 3 - thirdparty/sanitizers | 1 - thirdparty/sanitizers.cmake | 1 + thirdparty/sanitizers/.cmake-format.py | 248 +++++++++++++++++++ thirdparty/sanitizers/FindASan.cmake | 45 ++++ thirdparty/sanitizers/FindMSan.cmake | 49 ++++ thirdparty/sanitizers/FindSanitizers.cmake | 93 +++++++ thirdparty/sanitizers/FindTSan.cmake | 53 ++++ thirdparty/sanitizers/FindUBSan.cmake | 37 +++ thirdparty/sanitizers/asan-wrapper | 55 ++++ thirdparty/sanitizers/sanitize-helpers.cmake | 199 +++++++++++++++ 11 files changed, 780 insertions(+), 4 deletions(-) delete mode 100644 .gitmodules delete mode 160000 thirdparty/sanitizers create mode 100644 thirdparty/sanitizers.cmake create mode 100644 thirdparty/sanitizers/.cmake-format.py create mode 100644 thirdparty/sanitizers/FindASan.cmake create mode 100644 thirdparty/sanitizers/FindMSan.cmake create mode 100644 thirdparty/sanitizers/FindSanitizers.cmake create mode 100644 thirdparty/sanitizers/FindTSan.cmake create mode 100644 thirdparty/sanitizers/FindUBSan.cmake create mode 100755 thirdparty/sanitizers/asan-wrapper create mode 100644 thirdparty/sanitizers/sanitize-helpers.cmake diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index f2898f9..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "thirdparty/sanitizers"] - path = thirdparty/sanitizers - url = ../../f1x1t/cmake-sanitizers diff --git a/thirdparty/sanitizers b/thirdparty/sanitizers deleted file mode 160000 index f1abee3..0000000 --- a/thirdparty/sanitizers +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f1abee33655e414e7a1fca09640f98a1cb4f8b3d diff --git a/thirdparty/sanitizers.cmake b/thirdparty/sanitizers.cmake new file mode 100644 index 0000000..9a6bf02 --- /dev/null +++ b/thirdparty/sanitizers.cmake @@ -0,0 +1 @@ +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/sanitizers" ${CMAKE_MODULE_PATH}) diff --git a/thirdparty/sanitizers/.cmake-format.py b/thirdparty/sanitizers/.cmake-format.py new file mode 100644 index 0000000..4cdfbbf --- /dev/null +++ b/thirdparty/sanitizers/.cmake-format.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python3 + +# ---------------------------------- +# Options affecting listfile parsing +# ---------------------------------- +with section("parse"): + + # Specify structure for custom cmake functions + additional_commands = { + 'add_doxygen': { 'flags' : [], + 'kwargs': { 'LATEX': 1, + 'HTML': 1, + 'COMMENT': 1}}, + 'add_breathe': { 'flags' : [], + 'kwargs': { 'COMMENT': 1}}, + 'add_common_library': { 'flags' : [], + 'kwargs': { 'OUTPUT_NAME': 1, + 'SOURCES': '*', + 'TARGET': 1}}, + 'qt5_translation': { 'flags' : [], + 'kwargs': { 'OUTPUT_DIR': 1, + 'LANGUAGES': '*', + 'SOURCES': '*', + 'BASE_NAME': 1}}, + 'pvs_studio_add_target': { 'flags' : [ 'COMPILE_COMMANDS', + 'OUTPUT', + 'HIDE_HELP'], + 'kwargs': { 'ARGS': '*', + 'CONFIG': '*', + 'DEPENDS': '*', + 'FORMAT': '*', + 'MODE': '*', + 'TARGET': 1}}, + 'write_compiler_detection_header': { 'flags' : [], + 'kwargs': { 'COMPILERS': '*', + 'FEATURES': '*', + 'FILE': '*', + 'PREFIX': '*'}}} + + # Specify variable tags. + vartags = [] + + # Specify property tags. + proptags = [] + +# ----------------------------- +# Options affecting formatting. +# ----------------------------- +with section("format"): + + # How wide to allow formatted cmake files + line_width = 100 + + # How many spaces to tab for indent + tab_size = 4 + + # If an argument group contains more than this many sub-groups (parg or kwarg + # groups) then force it to a vertical layout. + max_subgroups_hwrap = 3 + + # If a positional argument group contains more than this many arguments, then + # force it to a vertical layout. + max_pargs_hwrap = 5 + + # If a cmdline positional group consumes more than this many lines without + # nesting, then invalidate the layout (and nest) + max_rows_cmdline = 2 + + # If true, separate flow control names from their parentheses with a space + separate_ctrl_name_with_space = False + + # If true, separate function names from parentheses with a space + separate_fn_name_with_space = False + + # If a statement is wrapped to more than one line, than dangle the closing + # parenthesis on its own line. + dangle_parens = False + + # If the trailing parenthesis must be 'dangled' on its on line, then align it + # to this reference: `prefix`: the start of the statement, `prefix-indent`: + # the start of the statement, plus one indentation level, `child`: align to + # the column of the arguments + dangle_align = 'prefix' + + # If the statement spelling length (including space and parenthesis) is + # smaller than this amount, then force reject nested layouts. + min_prefix_chars = 4 + + # If the statement spelling length (including space and parenthesis) is larger + # than the tab width by more than this amount, then force reject un-nested + # layouts. + max_prefix_chars = 2 + + # If a candidate layout is wrapped horizontally but it exceeds this many + # lines, then reject the layout. + max_lines_hwrap = 2 + + # What style line endings to use in the output. + line_ending = 'unix' + + # Format command names consistently as 'lower' or 'upper' case + command_case = 'canonical' + + # Format keywords consistently as 'lower' or 'upper' case + keyword_case = 'upper' + + # A list of command names which should always be wrapped + always_wrap = [] + + # If true, the argument lists which are known to be sortable will be sorted + # lexicographicall + enable_sort = True + + # If true, the parsers may infer whether or not an argument list is sortable + # (without annotation). + autosort = False + + # By default, if cmake-format cannot successfully fit everything into the + # desired linewidth it will apply the last, most agressive attempt that it + # made. If this flag is True, however, cmake-format will print error, exit + # with non-zero status code, and write-out nothing + require_valid_layout = False + + # A dictionary mapping layout nodes to a list of wrap decisions. See the + # documentation for more information. + layout_passes = {} + +# ------------------------------------------------ +# Options affecting comment reflow and formatting. +# ------------------------------------------------ +with section("markup"): + + # What character to use for bulleted lists + bullet_char = '*' + + # What character to use as punctuation after numerals in an enumerated list + enum_char = '.' + + # If comment markup is enabled, don't reflow the first comment block in each + # listfile. Use this to preserve formatting of your copyright/license + # statements. + first_comment_is_literal = False + + # If comment markup is enabled, don't reflow any comment block which matches + # this (regex) pattern. Default is `None` (disabled). + literal_comment_pattern = None + + # Regular expression to match preformat fences in comments default= + # ``r'^\s*([`~]{3}[`~]*)(.*)$'`` + fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$' + + # Regular expression to match rulers in comments default= + # ``r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'`` + ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$' + + # If a comment line matches starts with this pattern then it is explicitly a + # trailing comment for the preceeding argument. Default is '#<' + explicit_trailing_pattern = '#<' + + # If a comment line starts with at least this many consecutive hash + # characters, then don't lstrip() them off. This allows for lazy hash rulers + # where the first hash char is not separated by space + hashruler_min_length = 10 + + # If true, then insert a space between the first hash char and remaining hash + # chars in a hash ruler, and normalize its length to fill the column + canonicalize_hashrulers = True + + # enable comment markup parsing and reflow + enable_markup = False + +# ---------------------------- +# Options affecting the linter +# ---------------------------- +with section("lint"): + + # a list of lint codes to disable + disabled_codes = ['C0113'] + + # regular expression pattern describing valid function names + function_pattern = '[0-9a-z_]+' + + # regular expression pattern describing valid macro names + macro_pattern = '[0-9A-Z_]+' + + # regular expression pattern describing valid names for variables with global + # scope + global_var_pattern = '[0-9A-Z][0-9A-Z_]+' + + # regular expression pattern describing valid names for variables with global + # scope (but internal semantic) + internal_var_pattern = '_[0-9A-Z][0-9A-Z_]+' + + # regular expression pattern describing valid names for variables with local + # scope + local_var_pattern = '[0-9a-z_]+' + + # regular expression pattern describing valid names for privatedirectory + # variables + private_var_pattern = '_[0-9a-z_]+' + + # regular expression pattern describing valid names for publicdirectory + # variables + public_var_pattern = '[0-9A-Z][0-9A-Z_]+' + + # regular expression pattern describing valid names for keywords used in + # functions or macros + keyword_pattern = '[0-9A-Z_]+' + + # In the heuristic for C0201, how many conditionals to match within a loop in + # before considering the loop a parser. + max_conditionals_custom_parser = 2 + + # Require at least this many newlines between statements + min_statement_spacing = 1 + + # Require no more than this many newlines between statements + max_statement_spacing = 2 + max_returns = 6 + max_branches = 12 + max_arguments = 5 + max_localvars = 15 + max_statements = 50 + +# ------------------------------- +# Options affecting file encoding +# ------------------------------- +with section("encode"): + + # If true, emit the unicode byte-order mark (BOM) at the start of the file + emit_byteorder_mark = False + + # Specify the encoding of the input file. Defaults to utf-8 + input_encoding = 'utf-8' + + # Specify the encoding of the output file. Defaults to utf-8. Note that cmake + # only claims to support utf-8 so be careful when using anything else + output_encoding = 'utf-8' + +# ------------------------------------- +# Miscellaneous configurations options. +# ------------------------------------- +with section("misc"): + + # A dictionary containing any per-command configuration overrides. Currently + # only `command_case` is supported. + per_command = {} + diff --git a/thirdparty/sanitizers/FindASan.cmake b/thirdparty/sanitizers/FindASan.cmake new file mode 100644 index 0000000..9bdd10a --- /dev/null +++ b/thirdparty/sanitizers/FindASan.cmake @@ -0,0 +1,45 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault 2015-2016 RWTH Aachen University, Federal Republic of Germany +# 2021 Markus Eggenbauer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +# associated documentation files (the "Software"), to deal in the Software without restriction, +# including without limitation the rights to use, copy, modify, merge, publish, distribute, +# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all copies or +# substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +option(SANITIZE_ADDRESS "Enable AddressSanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES + # Clang 3.2+ use this version. The no-omit-frame-pointer option is optional. + "-g -fsanitize=address -fno-omit-frame-pointer" "-g -fsanitize=address" + # Older deprecated flag for ASan + "-g -faddress-sanitizer") + +include(sanitize-helpers) + +sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "AddressSanitizer" "ASan") + +find_program(ASan_WRAPPER "asan-wrapper" PATHS ${CMAKE_MODULE_PATH}) +mark_as_advanced(ASan_WRAPPER) + +function(add_sanitize_address TARGET) + # TODO: check conditions for target: + # if (SANITIZE_ADDRESS AND (SANITIZE_THREAD OR SANITIZE_MEMORY)) + # message(FATAL_ERROR "AddressSanitizer is not compatible with ThreadSanitizer or MemorySanitizer.") + # endif () + + sanitizer_check_target(${TARGET}) + sanitizer_add_flags(${TARGET} "AddressSanitizer" "ASan") +endfunction() diff --git a/thirdparty/sanitizers/FindMSan.cmake b/thirdparty/sanitizers/FindMSan.cmake new file mode 100644 index 0000000..38c98a5 --- /dev/null +++ b/thirdparty/sanitizers/FindMSan.cmake @@ -0,0 +1,49 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# 2021 Markus Eggenbauer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_MEMORY "Enable MemorySanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES "-g -fsanitize=memory") + +include(sanitize-helpers) + +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + message(NOTICE "MemorySanitizer disabled for target ${TARGET} because " + "MemorySanitizer is supported for Linux systems only.") +elseif(NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) + message(NOTICE "MemorySanitizer disabled for target ${TARGET} because " + "MemorySanitizer is supported for 64bit systems only.") +else() + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "MemorySanitizer" "MSan") +endif() + +function(add_sanitize_memory TARGET) + # TODO: check conditions for target: + # if (SANITIZE_MEMORY AND (SANITIZE_THREAD OR SANITIZE_ADDRESS)) + # message(FATAL_ERROR "AddressSanitizer is not compatible with ThreadSanitizer or MemorySanitizer.") + # endif () + sanitizer_check_target(${TARGET}) + sanitizer_add_flags(${TARGET} "MemorySanitizer" "MSan") +endfunction() diff --git a/thirdparty/sanitizers/FindSanitizers.cmake b/thirdparty/sanitizers/FindSanitizers.cmake new file mode 100644 index 0000000..bd6af85 --- /dev/null +++ b/thirdparty/sanitizers/FindSanitizers.cmake @@ -0,0 +1,93 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# 2021 Markus Eggenbauer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# If any of the used compiler is a GNU compiler, add a second option to static +# link against the sanitizers. +option(SANITIZE_LINK_STATIC "Try to link static against sanitizers." Off) + +set(FIND_QUIETLY_FLAG "") +if(DEFINED Sanitizers_FIND_QUIETLY) + set(FIND_QUIETLY_FLAG "QUIET") +endif() + +find_package(ASan ${FIND_QUIETLY_FLAG}) +find_package(TSan ${FIND_QUIETLY_FLAG}) +find_package(MSan ${FIND_QUIETLY_FLAG}) +find_package(UBSan ${FIND_QUIETLY_FLAG}) + +function(sanitizer_add_blacklist_file FILE) + if(NOT IS_ABSOLUTE ${FILE}) + set(FILE "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}") + endif() + get_filename_component(FILE "${FILE}" REALPATH) + + sanitizer_check_compiler_flags("-fsanitize-blacklist=${FILE}" "SanitizerBlacklist" "SanBlist") +endfunction() + +function(add_sanitizers ...) + # If no sanitizer is enabled, return immediately. + if(NOT + (SANITIZE_ADDRESS + OR SANITIZE_MEMORY + OR SANITIZE_THREAD + OR SANITIZE_UNDEFINED)) + return() + endif() + + if(SANITIZE_ADDRESS AND SANITIZE_THREAD) + message( + FATAL_ERROR + "Incompatible Sanitizer combination enabled: AddressSanitizer, ThreadSanitizer") + endif() + if(SANITIZE_ADDRESS AND SANITIZE_MEMORY) + message( + FATAL_ERROR + "Incompatible Sanitizer combination enabled: AddressSanitizer, MemorySanitizer") + endif() + + if(SANITIZE_MEMORY AND SANITIZE_THREAD) + message( + FATAL_ERROR + "Incompatible Sanitizer combination enabled: MemorySanitizer, ThreadSanitizer") + endif() + + foreach(TARGET ${ARGV}) + sanitizer_check_target(${TARGET}) + + # Add sanitizers for target. + if(SANITIZE_ADDRESS) + add_sanitize_address(${TARGET}) + endif() + if(SANITIZE_THREAD) + add_sanitize_thread(${TARGET}) + endif() + if(SANITIZE_MEMORY) + add_sanitize_memory(${TARGET}) + endif() + if(SANITIZE_UNDEFINED) + add_sanitize_undefined(${TARGET}) + endif() + endforeach() +endfunction(add_sanitizers) diff --git a/thirdparty/sanitizers/FindTSan.cmake b/thirdparty/sanitizers/FindTSan.cmake new file mode 100644 index 0000000..3c1c179 --- /dev/null +++ b/thirdparty/sanitizers/FindTSan.cmake @@ -0,0 +1,53 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# 2021 Markus Eggenbauer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_THREAD "Enable ThreadSanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES "-g -fsanitize=thread") + +include(sanitize-helpers) + +if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + message(NOTICE "ThreadSanitizer disabled for target ${TARGET} because " + "ThreadSanitizer is supported for Linux systems and macOS only.") + set(SANITIZE_THREAD Off CACHE BOOL "Enable ThreadSanitizer for sanitized targets." FORCE) +elseif(NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8) + message(NOTICE "ThreadSanitizer disabled for target ${TARGET} because " + "ThreadSanitizer is supported for 64bit systems only.") + set(SANITIZE_THREAD Off CACHE BOOL "Enable ThreadSanitizer for sanitized targets." FORCE) +else() + sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "ThreadSanitizer" "TSan") +endif() + +function(add_sanitize_thread TARGET) + # ThreadSanitizer is not compatible with MemorySanitizer. + # + # if(SANITIZE_THREAD AND SANITIZE_MEMORY) + # message(FATAL_ERROR "ThreadSanitizer is not compatible with " "MemorySanitizer.") + # endif() + + sanitizer_check_target(${TARGET}) + sanitizer_add_flags(${TARGET} "ThreadSanitizer" "TSan") +endfunction() diff --git a/thirdparty/sanitizers/FindUBSan.cmake b/thirdparty/sanitizers/FindUBSan.cmake new file mode 100644 index 0000000..c248d9c --- /dev/null +++ b/thirdparty/sanitizers/FindUBSan.cmake @@ -0,0 +1,37 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# 2021 Markus Eggenbauer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +option(SANITIZE_UNDEFINED "Enable UndefinedBehaviorSanitizer for sanitized targets." Off) + +set(FLAG_CANDIDATES "-g -fsanitize=undefined") + +include(sanitize-helpers) + +sanitizer_check_compiler_flags("${FLAG_CANDIDATES}" "UndefinedBehaviorSanitizer" "UBSan") + +function(add_sanitize_undefined TARGET) + sanitizer_check_target(${TARGET}) + sanitizer_add_flags(${TARGET} "UndefinedBehaviorSanitizer" "UBSan") +endfunction() diff --git a/thirdparty/sanitizers/asan-wrapper b/thirdparty/sanitizers/asan-wrapper new file mode 100755 index 0000000..5d54103 --- /dev/null +++ b/thirdparty/sanitizers/asan-wrapper @@ -0,0 +1,55 @@ +#!/bin/sh + +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This script is a wrapper for AddressSanitizer. In some special cases you need +# to preload AddressSanitizer to avoid error messages - e.g. if you're +# preloading another library to your application. At the moment this script will +# only do something, if we're running on a Linux platform. OSX might not be +# affected. + + +# Exit immediately, if platform is not Linux. +if [ "$(uname)" != "Linux" ] +then + exec $@ +fi + + +# Get the used libasan of the application ($1). If a libasan was found, it will +# be prepended to LD_PRELOAD. +libasan=$(ldd $1 | grep libasan | sed "s/^[[:space:]]//" | cut -d' ' -f1) +if [ -n "$libasan" ] +then + if [ -n "$LD_PRELOAD" ] + then + export LD_PRELOAD="$libasan:$LD_PRELOAD" + else + export LD_PRELOAD="$libasan" + fi +fi + +# Execute the application. +exec $@ diff --git a/thirdparty/sanitizers/sanitize-helpers.cmake b/thirdparty/sanitizers/sanitize-helpers.cmake new file mode 100644 index 0000000..93a326a --- /dev/null +++ b/thirdparty/sanitizers/sanitize-helpers.cmake @@ -0,0 +1,199 @@ +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# 2021 Markus Eggenbauer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# Helper function to get the language of a source file. +function(sanitizer_lang_of_source FILE RETURN_VAR) + get_filename_component(LONGEST_EXT "${FILE}" EXT) + # If extension is empty return. This can happen for extensionless headers + if("${LONGEST_EXT}" STREQUAL "") + set(${RETURN_VAR} "" PARENT_SCOPE) + return() + endif() + # Get shortest extension as some files can have dot in their names + string(REGEX REPLACE "^.*(\\.[^.]+)$" "\\1" FILE_EXT ${LONGEST_EXT}) + string(TOLOWER "${FILE_EXT}" FILE_EXT) + string(SUBSTRING "${FILE_EXT}" 1 -1 FILE_EXT) + + get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach(LANG ${ENABLED_LANGUAGES}) + list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${FILE_EXT}" TEMP) + if(NOT ${TEMP} EQUAL -1) + set(${RETURN_VAR} "${LANG}" PARENT_SCOPE) + return() + endif() + endforeach() + + set(${RETURN_VAR} "" PARENT_SCOPE) +endfunction() + +# Helper function to get compilers used by a target. +function(sanitizer_target_compilers TARGET RETURN_VAR) + # Check if all sources for target use the same compiler. If a target uses + # e.g. C and Fortran mixed and uses different compilers (e.g. clang and + # gfortran) this can trigger huge problems, because different compilers may + # use different implementations for sanitizers. + set(BUFFER "") + get_target_property(TSOURCES ${TARGET} SOURCES) + foreach(FILE ${TSOURCES}) + # If expression was found, FILE is a generator-expression for an object + # library. Object libraries will be ignored. + string(REGEX MATCH "TARGET_OBJECTS:([^ >]+)" _file ${FILE}) + if("${_file}" STREQUAL "") + sanitizer_lang_of_source(${FILE} LANG) + if(LANG) + list(APPEND BUFFER ${CMAKE_${LANG}_COMPILER_ID}) + endif() + endif() + endforeach() + + list(REMOVE_DUPLICATES BUFFER) + set(${RETURN_VAR} "${BUFFER}" PARENT_SCOPE) +endfunction() + +# Helper function to check compiler flags for language compiler. +function(sanitizer_check_compiler_flag FLAG LANG VARIABLE) + if(${LANG} STREQUAL "C") + include(CheckCCompilerFlag) + check_c_compiler_flag("${FLAG}" ${VARIABLE}) + + elseif(${LANG} STREQUAL "CXX") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("${FLAG}" ${VARIABLE}) + + elseif(${LANG} STREQUAL "Fortran") + # CheckFortranCompilerFlag was introduced in CMake 3.x. To be compatible + # with older Cmake versions, we will check if this module is present + # before we use it. Otherwise we will define Fortran coverage support as + # not available. + include(CheckFortranCompilerFlag OPTIONAL RESULT_VARIABLE INCLUDED) + if(INCLUDED) + CHECK_Fortran_COMPILER_FLAG("${FLAG}" ${VARIABLE}) + elseif(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VARIABLE}") + message(STATUS "Performing Test ${VARIABLE}" " - Failed (Check not supported)") + endif() + endif() +endfunction() + +# Helper function to test compiler flags. +function(sanitizer_check_compiler_flags FLAG_CANDIDATES NAME PREFIX) + set(CMAKE_REQUIRED_QUIET ${${PREFIX}_FIND_QUIETLY}) + + get_property(ENABLED_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) + foreach(LANG ${ENABLED_LANGUAGES}) + # Sanitizer flags are not dependend on language, but the used compiler. + # So instead of searching flags foreach language, search flags foreach + # compiler used. + set(COMPILER ${CMAKE_${LANG}_COMPILER_ID}) + if(NOT DEFINED ${PREFIX}_${COMPILER}_FLAGS) + foreach(FLAG ${FLAG_CANDIDATES}) + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Try ${COMPILER} ${NAME} flag = [${FLAG}]") + endif() + + set(CMAKE_REQUIRED_FLAGS "${FLAG}") + unset(${PREFIX}_FLAG_DETECTED CACHE) + sanitizer_check_compiler_flag("${FLAG}" ${LANG} ${PREFIX}_FLAG_DETECTED) + + if(${PREFIX}_FLAG_DETECTED) + # If compiler is a GNU compiler, search for static flag, if + # SANITIZE_LINK_STATIC is enabled. + if(SANITIZE_LINK_STATIC AND (${COMPILER} STREQUAL "GNU")) + string(TOLOWER ${PREFIX} PREFIX_lower) + sanitizer_check_compiler_flag("-static-lib${PREFIX_lower}" ${LANG} + ${PREFIX}_STATIC_FLAG_DETECTED) + + if(${PREFIX}_STATIC_FLAG_DETECTED) + set(FLAG "-static-lib${PREFIX_lower} ${FLAG}") + endif() + endif() + + set(${PREFIX}_${COMPILER}_FLAGS "${FLAG}" + CACHE STRING "${NAME} flags for ${COMPILER} compiler.") + mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) + break() + endif() + endforeach() + + if(NOT ${PREFIX}_FLAG_DETECTED) + set(${PREFIX}_${COMPILER}_FLAGS "" CACHE STRING + "${NAME} flags for ${COMPILER} compiler.") + mark_as_advanced(${PREFIX}_${COMPILER}_FLAGS) + + message( + NOTICE "${NAME} is not available for ${COMPILER} " + "compiler. Targets using this compiler will be " "compiled without ${NAME}.") + endif() + endif() + endforeach() +endfunction() + +# Helper to assign sanitizer flags for TARGET. +function(sanitizer_add_flags TARGET NAME PREFIX) + # Get list of compilers used by target and check, if sanitizer is available + # for this target. Other compiler checks like check for conflicting + # compilers will be done in add_sanitizers function. + sanitizer_target_compilers(${TARGET} TARGET_COMPILER) + list(LENGTH TARGET_COMPILER NUM_COMPILERS) + if("${${PREFIX}_${TARGET_COMPILER}_FLAGS}" STREQUAL "") + return() + endif() + + # Set compile- and link-flags for target. + set_property(TARGET ${TARGET} APPEND_STRING PROPERTY COMPILE_FLAGS + " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") + set_property(TARGET ${TARGET} APPEND_STRING PROPERTY COMPILE_FLAGS + " ${SanBlist_${TARGET_COMPILER}_FLAGS}") + set_property(TARGET ${TARGET} APPEND_STRING PROPERTY LINK_FLAGS + " ${${PREFIX}_${TARGET_COMPILER}_FLAGS}") +endfunction() + +macro(sanitizer_check_target TARGET) + # Check if this target will be compiled by exactly one compiler. Other- + # wise sanitizers can't be used and a warning should be printed once. + get_target_property(TARGET_TYPE ${TARGET} TYPE) + if(TARGET_TYPE STREQUAL "INTERFACE_LIBRARY") + message(NOTICE "Can't use any sanitizers for target ${TARGET}, " + "because it is an interface library and cannot be " "compiled directly.") + return() + endif() + sanitizer_target_compilers(${TARGET} TARGET_COMPILER) + list(LENGTH TARGET_COMPILER NUM_COMPILERS) + if(NUM_COMPILERS GREATER 1) + message( + NOTICE "Can't use any sanitizers for target ${TARGET}, " + "because it will be compiled by incompatible compilers. " + "Target will be compiled without sanitizers.") + return() + + # If the target is compiled by no or no known compiler, give a warning. + elseif(NUM_COMPILERS EQUAL 0) + message( + NOTICE "Sanitizers for target ${TARGET} may not be" + " usable, because it uses no or an unknown compiler. " + "This is a false warning for targets using only " "object lib(s) as input.") + return() + endif() +endmacro(sanitizer_check_target)