Merge pull request #287 from compnerd/sanitize

build: add support to build with sanitization
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f34e51..5d9e470 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,6 +25,7 @@
 set(WITH_BLOCKS_RUNTIME "" CACHE PATH "Path to blocks runtime")
 
 include(DispatchAppleOptions)
+include(DispatchSanitization)
 
 include(DispatchCompilerWarnings)
 dispatch_common_warnings()
diff --git a/cmake/modules/DispatchSanitization.cmake b/cmake/modules/DispatchSanitization.cmake
new file mode 100644
index 0000000..a0641f5
--- /dev/null
+++ b/cmake/modules/DispatchSanitization.cmake
@@ -0,0 +1,44 @@
+
+set(DISPATCH_USE_SANITIZER "" CACHE STRING
+    "Define the sanitizer used to build binaries and tests.")
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin AND DISPATCH_USE_SANITIZER)
+  message(FATAL_ERROR "building libdispatch with sanitization is not supported on Darwin")
+endif()
+
+if(DISPATCH_USE_SANITIZER)
+  # TODO(compnerd) ensure that the compiler supports these options before adding
+  # them.  At the moment, assume that this will just be used with a GNU
+  # compatible driver and that the options are spelt correctly in light of that.
+  add_compile_options("-fno-omit-frame-pointer")
+  if(CMAKE_BUILD_TYPE MATCHES "Debug")
+    add_compile_options("-O1")
+  elseif(NOT CMAKE_BUILD_TYPE MATCHES "Debug" AND
+         NOT CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
+    add_compile_options("-gline-tables-only")
+  endif()
+
+  if(LLVM_USE_SANITIZER STREQUAL "Address")
+    add_compile_options("-fsanitize=address")
+  elseif(DISPATCH_USE_SANITIZER MATCHES "Memory(WithOrigins)?")
+    add_compile_options("-fsanitize=memory")
+    if(DISPATCH_USE_SANITIZER STREQUAL "MemoryWithOrigins")
+    add_compile_options("-fsanitize-memory-track-origins")
+    endif()
+  elseif(DISPATCH_USE_SANITIZER STREQUAL "Undefined")
+    add_compile_options("-fsanitize=undefined")
+    add_compile_options("-fno-sanitize=vptr,function")
+    add_compile_options("-fno-sanitize-recover=all")
+  elseif(DISPATCH_USE_SANITIZER STREQUAL "Thread")
+    add_compile_options("-fsanitize=thread")
+  elseif(DISPATCH_USE_SANITIZER STREQUAL "Address;Undefined" OR
+         DISPATCH_USE_SANITIZER STREQUAL "Undefined;Address")
+    add_compile_options("-fsanitize=address,undefined")
+    add_compile_options("-fno-sanitize=vptr,function")
+    add_compile_options("-fno-sanitize-recover=all")
+  elseif(DISPATCH_USE_SANITIZER STREQUAL "Leaks")
+    add_compile_options("-fsanitize=leak")
+  else()
+    message(FATAL_ERROR "unsupported value of DISPATCH_USE_SANITIZER: ${DISPATCH_USE_SANITIZER}")
+  endif()
+endif()