mirror of
https://github.com/QuasarApp/pe-parse.git
synced 2025-04-26 12:24:32 +00:00
Makes it easier for CMake GUI interfaces to know this is a variable that takes in different strings instead of a boolean.
175 lines
7.0 KiB
CMake
175 lines
7.0 KiB
CMake
# Enable C/C++ sanitizers in your CMake project by `include`ing this file
|
|
# somewhere in your CMakeLists.txt.
|
|
#
|
|
# Example:
|
|
#
|
|
# include("cmake/sanitizers.cmake")
|
|
# process_sanitizer(MY_PROJECT)
|
|
#
|
|
# Example CMake configuration usage for `MY_PROJECT`:
|
|
#
|
|
# cmake -Bbuild-asan-ubsan -H. -DMY_PROJECT_USE_SANITIZER=Address,Undefined
|
|
#
|
|
# where "MY_PROJECT" can by any arbitrary text that will be prepended to some
|
|
# expected CMake variables--see below.
|
|
#
|
|
# This file expects the following variables to be set during CMake
|
|
# configuration, where the prefix is set by the caller of `process_sanitizer`:
|
|
#
|
|
# - *_USE_SANITIZER
|
|
# - A string value that is one of the following:
|
|
# - Address
|
|
# - HWAddress
|
|
# - Memory
|
|
# - MemoryWithOrigins
|
|
# - Undefined
|
|
# - Thread
|
|
# - DataFlow
|
|
# - Leak
|
|
# - Address,Undefined
|
|
#
|
|
# - *_OPTIMIZE_SANITIZED_BUILDS
|
|
# - A boolean value to set whether a higher optimization is used in debug
|
|
# builds
|
|
#
|
|
# - *_BLACKLIST_FILE
|
|
# - A filepath to a sanitizer blacklist file.
|
|
|
|
|
|
function(append value)
|
|
foreach(variable ${ARGN})
|
|
set(${variable}
|
|
"${${variable}} ${value}"
|
|
PARENT_SCOPE)
|
|
endforeach(variable)
|
|
endfunction()
|
|
|
|
|
|
macro(append_common_sanitizer_flags prefix)
|
|
if (NOT MSVC)
|
|
# Append -fno-omit-frame-pointer and turn on debug info to get better
|
|
# stack traces.
|
|
append("-fno-omit-frame-pointer" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
append("-fno-optimize-sibling-calls" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
append("-gline-tables-only" CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE
|
|
CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZE_REL)
|
|
# Use -O1 even in debug mode, otherwise sanitizers slowdown is too large.
|
|
if (${prefix}_OPTIMIZE_SANITIZED_BUILDS)
|
|
message(STATUS "Optimizing sanitized Debug build")
|
|
append("-O1" CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG)
|
|
endif()
|
|
else()
|
|
# Keep frame pointers around.
|
|
append("/Oy-" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
# Always ask the linker to produce symbols with asan.
|
|
append("/Zi" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
# Workaround for incompatible (warning-producing) default CMake flag
|
|
# https://docs.microsoft.com/en-us/cpp/sanitizers/asan-known-issues
|
|
# https://gitlab.kitware.com/cmake/cmake/-/issues/19084
|
|
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
|
append("/debug" CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS)
|
|
endif()
|
|
endmacro()
|
|
|
|
|
|
# Main logic
|
|
macro(process_sanitizer prefix)
|
|
|
|
# Add options for the project to use sanitizers
|
|
set(${prefix}_USE_SANITIZER "false" CACHE STRING "Enable building with sanitizer support.")
|
|
set_property(CACHE ${prefix}_USE_SANITIZER PROPERTY STRINGS Address HWAddress Memory MemoryWithOrigins Undefined Thread DataFlow Leak "Address,Undefined")
|
|
if (UNIX)
|
|
option(${prefix}_OPTIMIZE_SANITIZED_BUILDS "Optimize builds that use sanitization" false)
|
|
option(${prefix}_BLACKLIST_FILE "Path to blacklist file for sanitizers" "")
|
|
option(${prefix}_USE_SANITIZE_COVERAGE "Set for libFuzzer-required instrumentation, no linking." false)
|
|
endif()
|
|
|
|
if (${prefix}_USE_SANITIZER)
|
|
if(UNIX)
|
|
|
|
if(${prefix}_USE_SANITIZER STREQUAL "Address")
|
|
message(STATUS "Building with Address sanitizer")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
elseif(${prefix}_USE_SANITIZER STREQUAL "HWAddress")
|
|
message(STATUS "Building with Address sanitizer")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=hwaddress" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
elseif(${prefix}_USE_SANITIZER MATCHES "Memory(WithOrigins)?")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=memory" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
if(${prefix}_USE_SANITIZER STREQUAL "MemoryWithOrigins")
|
|
message(STATUS "Building with MemoryWithOrigins sanitizer")
|
|
append("-fsanitize-memory-track-origins" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
else()
|
|
message(STATUS "Building with Memory sanitizer")
|
|
endif()
|
|
|
|
elseif(${prefix}_USE_SANITIZER STREQUAL "Undefined")
|
|
message(STATUS "Building with Undefined sanitizer")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
# Execution error on undefined detection. Could be optional to add this
|
|
append("-fno-sanitize-recover=all" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
elseif(${prefix}_USE_SANITIZER STREQUAL "Thread")
|
|
message(STATUS "Building with Thread sanitizer")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=thread" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
elseif(${prefix}_USE_SANITIZER STREQUAL "DataFlow")
|
|
message(STATUS "Building with DataFlow sanitizer")
|
|
append("-fsanitize=dataflow" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
elseif(${prefix}_USE_SANITIZER STREQUAL "Leak")
|
|
message(STATUS "Building with Leak sanitizer")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=leak" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
elseif(${prefix}_USE_SANITIZER STREQUAL "Address,Undefined"
|
|
OR ${prefix}_USE_SANITIZER STREQUAL "Undefined,Address")
|
|
message(STATUS "Building with Address, Undefined sanitizers")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("-fsanitize=address,undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
# Execution error on undefined detection. Could be optional to add this
|
|
append("-fno-sanitize-recover=all" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
|
|
else()
|
|
message(
|
|
FATAL_ERROR "Unsupported value of ${prefix}_USE_SANITIZER: '${${prefix}_USE_SANITIZER}'")
|
|
endif()
|
|
elseif(MSVC)
|
|
if(${prefix}_USE_SANITIZER STREQUAL "Address")
|
|
message(STATUS "Building with Address sanitizer")
|
|
append_common_sanitizer_flags(${prefix})
|
|
append("/fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
else()
|
|
message(FATAL_ERROR "This sanitizer is not yet supported in the MSVC environment: '${${prefix}_USE_SANITIZER}'")
|
|
endif()
|
|
else()
|
|
message(FATAL_ERROR "${prefix}_USE_SANITIZER is not supported on this platform.")
|
|
endif()
|
|
|
|
# If specified, use a blacklist file
|
|
if (EXISTS "${${prefix}_BLACKLIST_FILE}")
|
|
message(STATUS "Using sanitizer blacklist file: ${${prefix}_BLACKLIST_FILE}")
|
|
append("-fsanitize-blacklist=${${prefix}_BLACKLIST_FILE}" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
endif()
|
|
|
|
# Set a once non-default option for more detection
|
|
if (${prefix}_USE_SANITIZER MATCHES "(Undefined,)?Address(,Undefined)?")
|
|
if (UNIX)
|
|
append("-fsanitize-address-use-after-scope" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
endif()
|
|
endif()
|
|
|
|
# Set for libFuzzer-required instrumentation, no linking.
|
|
if (${prefix}_USE_SANITIZE_COVERAGE)
|
|
message(STATUS "Setting up sanitizer for coverage support with 'fuzzer-no-link'")
|
|
append("-fsanitize=fuzzer-no-link" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
|
|
endif()
|
|
endif()
|
|
endmacro()
|