arsenm / sanitizers-cmake

CMake modules to help use sanitizers
Other
377 stars 65 forks source link

How do I check the sanitizer is available? #8

Closed tom-seddon closed 7 years ago

tom-seddon commented 7 years ago

There doesn't seem to be any way to tell whether the requested sanitizer will actually be used. Like, suppose you ask for the memory sanitizer, but it isn't available.

CMake Warning at submodules/sanitizers-cmake/cmake/FindMSan.cmake:36 (message):
  MemorySanitizer disabled for target because MemorySanitizer is supported
  for Linux systems only.
Call Stack (most recent call first):
  submodules/sanitizers-cmake/cmake/FindSanitizers.cmake:39 (find_package)
  CMakeLists.txt:18 (find_package)

How can you tell when this happens? I want to be able to check with an if so the build can stop when the sanitizer isn't available.

I'm hoping I've missed something but if not then I can (try to) add this functionality it.

Thanks,

--Tom

alehaa commented 7 years ago

This message says, that you've tried to use memory sanitizer, but it is not supported at your platform - so it won't be used.

In general: if you enable some sanitizers, a message for searching the sanitizers flag will be printed. If there are no other messages, the sanitizer will be used. If there are messages, they'll tell you why a specific sanitizer can't be used for a specific target.

tom-seddon commented 7 years ago

Can I test for this with an if in my cmakelists.txt? I want to print a fatal error message if the sanitizer is unavailable, so the build won't continue.

Lots of cmake projects seem to print out a lot of stuff to the screen, or at least the ones I'm using do. The sanitizer-related output is easy to miss. All I'm going to do if the sanitizer isn't available is give up anyway.

Thanks,

--Tom

alehaa commented 7 years ago

There is no specific variable, but you may check if <SAN>_${CMAKE_<LANG>_COMPILER_ID}_FLAGS is set, where <SAN> is one of ASan, MSan, TSan or UBSan.

tom-seddon commented 7 years ago

Thanks for the suggestion. The following seems to work, for my purposes at least.

set(WANTED_SANITIZE_THREAD ${SANITIZE_THREAD})
set(WANTED_SANITIZE_UNDEFINED ${SANITIZE_UNDEFINED})
set(WANTED_SANITIZE_MEMORY ${SANITIZE_MEMORY})
set(WANTED_SANITIZE_ADDRESS ${SANITIZE_ADDRESS})

find_package(Sanitizers)

function(check_sanitizer NAME PREFIX)
  if(WANTED_SANITIZE_${NAME})
    if("${${PREFIX}_${CMAKE_C_COMPILER_ID}_FLAGS}" STREQUAL "")
      message(FATAL_ERROR ${NAME} " sanitizer not available")
    endif()
  endif()
endfunction()

check_sanitizer(THREAD TSan)
check_sanitizer(UNDEFINED UBSan)
check_sanitizer(MEMORY MSan)
check_sanitizer(ADDRESS ASan)

--Tom

alehaa commented 7 years ago

Yes, this should work fine. But attention: this covers only C. You need to call this code a second, third, ... time for other enabled languages to cover all. But if you're only using C, than it's fine.