blob: ad0a72122682eaa9370b5e4d8c0fd24393689d1e [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Configuration for code analysis tools.
#
# The RUNTIME_CHECK variable enables run-time checking when running
# the CTest test suite. The following tools are supported
#
# -DRUNTIME_CHECK=tsan # turns on thread sanitizer
# -DRUNTIME_CHECK=asan # address and undefined behavior sanitizer
# -DRUNTIME_CHECK=hwasan # hardware-supported asan for aarch64
# -DRUNTIME_CHECK=memcheck # valgrind memcheck (in progress)
# -DRUNTIME_CHECK=helgrind # valgrind helgrind (in progress)
#
# This file updates the QDROUTERD_RUNNER and CMAKE_C_FLAGS
# appropriately for use when running the ctest suite.
# Valgrind configuration
#
find_program(VALGRIND_EXECUTABLE valgrind DOC "Location of the valgrind program")
set(VALGRIND_SUPPRESSIONS "${CMAKE_SOURCE_DIR}/tests/valgrind.supp" CACHE STRING "Suppressions file for valgrind")
set(VALGRIND_COMMON_ARGS "--error-exitcode=42 --xml=yes --xml-file=valgrind-%p.xml --quiet --suppressions=${VALGRIND_SUPPRESSIONS}")
mark_as_advanced(VALGRIND_EXECUTABLE VALGRIND_SUPPRESSIONS VALGRIND_COMMON_ARGS)
macro(assert_has_valgrind)
if(NOT VALGRIND_EXECUTABLE)
message(FATAL_ERROR "valgrind is not available")
endif()
endmacro()
# Check for compiler's support of sanitizers.
# Currently have tested back to gcc 5.4.0 and clang 6.0.0, older
# versions may require more work
#
if((CMAKE_C_COMPILER_ID MATCHES "GNU"
AND (CMAKE_C_COMPILER_VERSION VERSION_GREATER 5.4
OR CMAKE_C_COMPILER_VERSION VERSION_EQUAL 5.4))
OR (CMAKE_C_COMPILER_ID MATCHES "Clang"
AND (CMAKE_C_COMPILER_VERSION VERSION_GREATER 6.0
OR CMAKE_C_COMPILER_VERSION VERSION_EQUAL 6.0)))
set(HAS_SANITIZERS TRUE)
endif()
macro(assert_has_sanitizers)
if(NOT HAS_SANITIZERS)
message(FATAL_ERROR "compiler sanitizers are not available")
endif()
endmacro()
# Valid options for RUNTIME_CHECK
#
set(runtime_checks OFF tsan asan hwasan memcheck helgrind)
# Set RUNTIME_CHECK value and deal with the older cmake flags for
# valgrind and TSAN
#
set(RUNTIME_CHECK_DEFAULT OFF)
macro(deprecated_enable_check old new doc)
if (${old})
message("WARNING: option ${old} is deprecated, use -DRUNTIME_CHECK=${new} instead")
set(RUNTIME_CHECK_DEFAULT ${new})
endif()
unset(${old} CACHE)
endmacro()
option(VALGRIND_XML "Write valgrind output as XML (DEPRECATED)" OFF)
deprecated_enable_check(USE_VALGRIND memcheck "Use valgrind to detect run-time problems")
deprecated_enable_check(USE_TSAN tsan "Compile with thread sanitizer (tsan)")
set(RUNTIME_CHECK ${RUNTIME_CHECK_DEFAULT} CACHE STRING "Enable runtime checks. Valid values: ${runtime_checks}")
if(CMAKE_BUILD_TYPE MATCHES "Coverage" AND RUNTIME_CHECK)
message(FATAL_ERROR "Cannot set RUNTIME_CHECK with CMAKE_BUILD_TYPE=Coverage")
endif()
if(RUNTIME_CHECK STREQUAL "memcheck")
assert_has_valgrind()
message(STATUS "Runtime memory checker: valgrind memcheck")
set(QDROUTERD_RUNNER "${VALGRIND_EXECUTABLE} --tool=memcheck --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite ${VALGRIND_COMMON_ARGS}")
elseif(RUNTIME_CHECK STREQUAL "helgrind")
assert_has_valgrind()
message(STATUS "Runtime race checker: valgrind helgrind")
set(QDROUTERD_RUNNER "${VALGRIND_EXECUTABLE} --tool=helgrind ${VALGRIND_COMMON_ARGS}")
elseif(RUNTIME_CHECK STREQUAL "asan" OR RUNTIME_CHECK STREQUAL "hwasan")
assert_has_sanitizers()
find_library(ASAN_LIBRARY NAME asan libasan)
if(ASAN_LIBRARY-NOTFOUND)
message(FATAL_ERROR "libasan not installed - address sanitizer not available")
endif(ASAN_LIBRARY-NOTFOUND)
find_library(UBSAN_LIBRARY NAME ubsan libubsan)
if(UBSAN_LIBRARY-NOTFOUND)
message(FATAL_ERROR "libubsan not installed - address sanitizer not available")
endif(UBSAN_LIBRARY-NOTFOUND)
if(RUNTIME_CHECK STREQUAL "asan")
set(ASAN_VARIANTS "address,undefined")
elseif(RUNTIME_CHECK STREQUAL "hwasan")
set(ASAN_VARIANTS "hwaddress,undefined")
# hwasan currently needs lld, otherwise binaries crash on invalid instruction
# https://github.com/google/sanitizers/issues/1241
add_link_options("-fuse-ld=lld")
endif()
message(STATUS "Runtime memory checker: gcc/clang address sanitizers: ${ASAN_VARIANTS}")
option(SANITIZE_3RD_PARTY "Detect leaks in 3rd party libraries used by Dispatch while running tests" OFF)
if (SANITIZE_3RD_PARTY)
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/tests/lsan.supp
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/tests/lsan.supp ${CMAKE_BINARY_DIR}/tests/lsan.supp
DEPENDS ${CMAKE_SOURCE_DIR}/tests/lsan.supp
VERBATIM)
else (SANITIZE_3RD_PARTY)
# Append wholesale library suppressions
# this is necessary if target system does not have debug symbols for these libraries installed
# and therefore the more specific suppressions do not match
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/tests/lsan.supp
COMMAND bash -c 'cat ${CMAKE_SOURCE_DIR}/tests/lsan.supp ${CMAKE_SOURCE_DIR}/tests/lsan_3rdparty.supp > ${CMAKE_BINARY_DIR}/tests/lsan.supp'
DEPENDS ${CMAKE_SOURCE_DIR}/tests/lsan.supp ${CMAKE_SOURCE_DIR}/tests/lsan_3rdparty.supp)
endif ()
add_custom_target(generate_lsan.supp ALL
DEPENDS ${CMAKE_BINARY_DIR}/tests/lsan.supp)
# force QD_MEMORY_DEBUG else lsan will catch alloc_pool suppressed leaks (ok to remove this once leaks are fixed)
set(SANITIZE_FLAGS "-g -fno-omit-frame-pointer -fsanitize=${ASAN_VARIANTS} -DQD_MEMORY_DEBUG=1")
# `detect_leaks=1` is set by default where it is available; better not to set it conditionally ourselves
# https://github.com/openSUSE/systemd/blob/1270e56526cd5a3f485ae2aba975345c38860d37/docs/TESTING_WITH_SANITIZERS.md
# TODO(DISPATCH-2148) re-enable odr violation detection when Proton linking issue in test-sender is fixed
set(RUNTIME_ASAN_ENV_OPTIONS "detect_odr_violation=0 strict_string_checks=1 detect_stack_use_after_return=1 check_initialization_order=1 strict_init_order=1 detect_invalid_pointer_pairs=2 suppressions=${CMAKE_SOURCE_DIR}/tests/asan.supp")
set(RUNTIME_LSAN_ENV_OPTIONS "suppressions=${CMAKE_BINARY_DIR}/tests/lsan.supp")
set(RUNTIME_UBSAN_ENV_OPTIONS "print_stacktrace=1 print_summary=1")
elseif(RUNTIME_CHECK STREQUAL "tsan")
assert_has_sanitizers()
find_library(TSAN_LIBRARY NAME tsan libtsan)
if(TSAN_LIBRARY-NOTFOUND)
message(FATAL_ERROR "libtsan not installed - thread sanitizer not available")
endif(TSAN_LIBRARY-NOTFOUND)
message(STATUS "Runtime race checker: gcc/clang thread sanitizer")
set(SANITIZE_FLAGS "-g -fno-omit-frame-pointer -fsanitize=thread")
set(RUNTIME_TSAN_ENV_OPTIONS "history_size=4 second_deadlock_stack=1 suppressions=${CMAKE_SOURCE_DIR}/tests/tsan.supp")
elseif(RUNTIME_CHECK)
message(FATAL_ERROR "'RUNTIME_CHECK=${RUNTIME_CHECK}' is invalid, valid values: ${runtime_checks}")
endif()