From 42d3ec99172aa644044923678943a70a8c31955c Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 1 Aug 2016 05:19:21 +0000 Subject: [PATCH] CMake: finish Clang sanitizer support. This makes ENABLE_SANITIZERS a proper cached variable, removes some spurious failures and configures asan/ubsan to die on an error. --- .travis/build-debian.sh | 6 ++++-- CMakeLists.txt | 14 ++++++++++---- src/resource.cpp | 14 +++++++++----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/.travis/build-debian.sh b/.travis/build-debian.sh index 2b6db43..e88bd9a 100755 --- a/.travis/build-debian.sh +++ b/.travis/build-debian.sh @@ -4,6 +4,8 @@ if echo $TRAVIS_TAG | grep ^v; then BUILD_TYPE=RelWithDebInfo; else BUILD_TYPE=D mkdir build cd build -cmake -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5 \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DENABLE_COVERAGE=ON .. +cmake .. -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_CXX_COMPILER=g++-5 \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DENABLE_COVERAGE=ON \ + -DENABLE_SANITIZERS=ON make VERBOSE=1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 15f2365..baa3c16 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,10 +27,12 @@ set(solvespace_VERSION_MAJOR 3) set(solvespace_VERSION_MINOR 0) string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 solvespace_GIT_HASH) -set(ENABLE_TESTS ON CACHE BOOL +set(ENABLE_TESTS ON CACHE BOOL "Whether the test suite will be built and run") -set(ENABLE_COVERAGE OFF CACHE BOOL +set(ENABLE_COVERAGE OFF CACHE BOOL "Whether code coverage information will be collected") +set(ENABLE_SANITIZERS OFF CACHE BOOL + "Whether to enable Clang's AddressSanitizer and UndefinedBehaviorSanitizer") if(NOT WIN32 AND NOT APPLE) set(GUI gtk2 CACHE STRING "GUI toolkit to use (one of: gtk2 gtk3)") @@ -58,12 +60,16 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}") endif() -if(SANITIZE) +if(ENABLE_SANITIZE) if(NOT (CMAKE_C_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - message(ERROR "Sanitizers are only available in Clang/Clang++") + message(FATAL_ERROR "Sanitizers are only available when using Clang/Clang++") endif() set(SANITIZE_FLAGS "-O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls") set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fsanitize=address,undefined,integer") + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fno-sanitize-recover=undefined,integer") + # We assume IEEE floats, which means DIV/0 is defined; but ubsan doesn't do so by default. + set(SANITIZE_FLAGS "${SANITIZE_FLAGS} -fno-sanitize=float-divide-by-zero") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}") endif() diff --git a/src/resource.cpp b/src/resource.cpp index 3393e16..7980b57 100644 --- a/src/resource.cpp +++ b/src/resource.cpp @@ -21,8 +21,8 @@ std::string LoadString(const std::string &name) { } std::string LoadStringFromGzip(const std::string &name) { - size_t size; - const void *data = LoadResource(name, &size); + size_t deflatedSize; + const void *data = LoadResource(name, &deflatedSize); z_stream stream; stream.zalloc = Z_NULL; @@ -33,11 +33,15 @@ std::string LoadStringFromGzip(const std::string &name) { // Extract length mod 2**32 from the gzip trailer. std::string result; - ssassert(size >= 4, "Resource too small to have gzip trailer"); - result.resize(*(uint32_t *)((uintptr_t)data + size - 4)); + ssassert(deflatedSize >= 4, "Resource too small to have gzip trailer"); + + // *(uint32_t *) may perform an unaligned access, so do a memcpy. + uint32_t inflatedSize; + memcpy(&inflatedSize, (uint32_t *)((uintptr_t)data + deflatedSize - 4), sizeof(uint32_t)); + result.resize(inflatedSize); stream.next_in = (Bytef *)data; - stream.avail_in = size; + stream.avail_in = deflatedSize; stream.next_out = (Bytef *)&result[0]; stream.avail_out = result.length(); ssassert(inflate(&stream, Z_NO_FLUSH) == Z_STREAM_END, "Cannot inflate resource");