diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 27b4a7ddb5c..edd232138b0 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -114,6 +114,7 @@ endif() add_contrib (llvm-project-cmake llvm-project) add_contrib (libfuzzer-cmake llvm-project) +add_contrib (gwpasan-cmake llvm-project) add_contrib (libxml2-cmake libxml2) add_contrib (aws-cmake diff --git a/contrib/gwpasan-cmake/CMakeLists.txt b/contrib/gwpasan-cmake/CMakeLists.txt new file mode 100644 index 00000000000..33268d68bf1 --- /dev/null +++ b/contrib/gwpasan-cmake/CMakeLists.txt @@ -0,0 +1,41 @@ +set(COMPILER_RT_GWP_ASAN_SRC_DIR "${ClickHouse_SOURCE_DIR}/contrib/llvm-project/compiler-rt/lib/gwp_asan") + +set(GWP_ASAN_SOURCES + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/common.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/crash_handler.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/common_posix.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/guarded_pool_allocator_posix.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/mutex_posix.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/utilities_posix.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/guarded_pool_allocator.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/stack_trace_compressor.cpp + ${COMPILER_RT_GWP_ASAN_SRC_DIR}/optional/options_parser.cpp + #PARENT_SCOPE +) + +#set(GWP_ASAN_LIBS RTGwpAsan RTGwpAsanOptionsParser RTGwpAsanBacktraceLibc RTGwpAsanSegvHandler) + +set(GWP_ASAN_HEADERS "${ClickHouse_SOURCE_DIR}/contrib/llvm-project/compiler-rt/lib") + +#set(GWP_ASAN_HEADERS_FILES +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/common.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/crash_handler.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/definitions.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/guarded_pool_allocator.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/mutex.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/options.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/options.inc +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/guarded_pool_allocator_fuchsia.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/guarded_pool_allocator_posix.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/guarded_pool_allocator_tls.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/mutex_fuchsia.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/platform_specific/mutex_posix.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/stack_trace_compressor.h +# ${COMPILER_RT_GWP_ASAN_SRC_DIR}/utilities.h +# PARENT_SCOPE +#) + +add_library(_gwp_asan ${GWP_ASAN_SOURCES}) +#target_link_libraries (_gwp_asan INTERFACE ${GWP_ASAN_SOURCES}) +target_include_directories (_gwp_asan SYSTEM PUBLIC ${GWP_ASAN_HEADERS}) +add_library(ch_contrib::gwp_asan ALIAS _gwp_asan) diff --git a/programs/main.cpp b/programs/main.cpp index 389eae92091..67e0b509aaa 100644 --- a/programs/main.cpp +++ b/programs/main.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -433,7 +434,6 @@ extern "C" } #endif - /// This allows to implement assert to forbid initialization of a class in static constructors. /// Usage: /// @@ -465,6 +465,8 @@ int main(int argc_, char ** argv_) /// It is needed because LLVM library clobbers it. std::set_new_handler(nullptr); + Memory::initGWPAsan(); + std::vector argv(argv_, argv_ + argc_); /// Print a basic help if nothing was matched diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d8a7dba72ac..c26ba46a90f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -310,6 +310,11 @@ if (TARGET ch_contrib::llvm) dbms_target_link_libraries (PUBLIC ch_contrib::llvm) endif () +if (TARGET ch_contrib::gwp_asan) + target_link_libraries (clickhouse_common_io PUBLIC ch_contrib::gwp_asan) + target_link_libraries (clickhouse_new_delete PRIVATE ch_contrib::gwp_asan) +endif() + # Otherwise it will slow down stack traces printing too much. set_source_files_properties( Common/Elf.cpp diff --git a/src/Common/gwp_asan.h b/src/Common/gwp_asan.h new file mode 100644 index 00000000000..ecbe4fe7b8d --- /dev/null +++ b/src/Common/gwp_asan.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include +#include + +namespace Memory +{ + +static gwp_asan::GuardedPoolAllocator GuardedAlloc; + +inline ALWAYS_INLINE void initGWPAsan() +{ + gwp_asan::options::initOptions(); + gwp_asan::options::Options &opts = gwp_asan::options::getOptions(); + GuardedAlloc.init(opts); +} + +} diff --git a/src/Common/memory.h b/src/Common/memory.h index 4cb1c535e56..d6038fd3bac 100644 --- a/src/Common/memory.h +++ b/src/Common/memory.h @@ -7,6 +7,7 @@ #include #include +#include #include "config.h" #if USE_JEMALLOC @@ -29,6 +30,21 @@ template ... TAlign> requires DB::OptionalArgument inline ALWAYS_INLINE void * newImpl(std::size_t size, TAlign... align) { + if (unlikely(GuardedAlloc.shouldSample())) + { + if constexpr (sizeof...(TAlign) == 1) + { + if (void * ptr = GuardedAlloc.allocate(size, alignToSizeT(align...))) + return ptr; + } + else + { + if (void * ptr = GuardedAlloc.allocate(size)) + return ptr; + + } + } + void * ptr = nullptr; if constexpr (sizeof...(TAlign) == 1) ptr = aligned_alloc(alignToSizeT(align...), size); @@ -44,16 +60,31 @@ inline ALWAYS_INLINE void * newImpl(std::size_t size, TAlign... align) inline ALWAYS_INLINE void * newNoExept(std::size_t size) noexcept { + if (unlikely(GuardedAlloc.shouldSample())) + { + if (void * ptr = GuardedAlloc.allocate(size)) + return ptr; + } return malloc(size); } inline ALWAYS_INLINE void * newNoExept(std::size_t size, std::align_val_t align) noexcept { + if (unlikely(GuardedAlloc.shouldSample())) + { + if (void * ptr = GuardedAlloc.allocate(size, alignToSizeT(align))) + return ptr; + } return aligned_alloc(static_cast(align), size); } inline ALWAYS_INLINE void deleteImpl(void * ptr) noexcept { + if (unlikely(GuardedAlloc.pointerIsMine(ptr))) + { + GuardedAlloc.deallocate(ptr); + return; + } free(ptr); } @@ -66,6 +97,12 @@ inline ALWAYS_INLINE void deleteSized(void * ptr, std::size_t size, TAlign... al if (unlikely(ptr == nullptr)) return; + if (unlikely(GuardedAlloc.pointerIsMine(ptr))) + { + GuardedAlloc.deallocate(ptr); + return; + } + if constexpr (sizeof...(TAlign) == 1) sdallocx(ptr, size, MALLOCX_ALIGN(alignToSizeT(align...))); else @@ -122,6 +159,14 @@ template ... TAlign> requires DB::OptionalArgument inline ALWAYS_INLINE void untrackMemory(void * ptr [[maybe_unused]], std::size_t size [[maybe_unused]] = 0, TAlign... align [[maybe_unused]]) noexcept { + if (unlikely(GuardedAlloc.pointerIsMine(ptr))) + { + if (!size) + size = GuardedAlloc.getSize(ptr); + CurrentMemoryTracker::free(size); + return; + } + try { #if USE_JEMALLOC