Index: compiler-rt/trunk/lib/hwasan/hwasan.h =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan.h +++ compiler-rt/trunk/lib/hwasan/hwasan.h @@ -77,7 +77,6 @@ void HwasanAllocatorInit(); void HwasanAllocatorThreadFinish(); -void HwasanDeallocate(StackTrace *stack, void *ptr); void *hwasan_malloc(uptr size, StackTrace *stack); void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack); @@ -88,6 +87,7 @@ void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack); int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size, StackTrace *stack); +void hwasan_free(void *ptr, StackTrace *stack); void InstallTrapHandler(); void InstallAtExitHandler(); Index: compiler-rt/trunk/lib/hwasan/hwasan_allocator.h =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_allocator.h +++ compiler-rt/trunk/lib/hwasan/hwasan_allocator.h @@ -14,6 +14,7 @@ #ifndef HWASAN_ALLOCATOR_H #define HWASAN_ALLOCATOR_H +#include "interception/interception.h" #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" @@ -26,6 +27,11 @@ #error Unsupported platform #endif +#if HWASAN_WITH_INTERCEPTORS +DECLARE_REAL(void *, realloc, void *ptr, uptr size) +DECLARE_REAL(void, free, void *ptr) +#endif + namespace __hwasan { struct Metadata { Index: compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_allocator.cc @@ -21,6 +21,11 @@ #include "hwasan_thread.h" #include "hwasan_report.h" +#if HWASAN_WITH_INTERCEPTORS +DEFINE_REAL(void *, realloc, void *ptr, uptr size) +DEFINE_REAL(void, free, void *ptr) +#endif + namespace __hwasan { static Allocator allocator; @@ -199,7 +204,7 @@ return ptr_tag == mem_tag; } -void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { +static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK(tagged_ptr); HWASAN_FREE_HOOK(tagged_ptr); @@ -253,8 +258,8 @@ } } -void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, uptr new_size, - uptr alignment) { +static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, + uptr new_size, uptr alignment) { if (!PointerAndMemoryTagsMatch(tagged_ptr_old)) ReportInvalidFree(stack, reinterpret_cast(tagged_ptr_old)); @@ -271,7 +276,7 @@ return tagged_ptr_new; } -void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) { +static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) { if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { if (AllocatorMayReturnNull()) return nullptr; @@ -315,6 +320,14 @@ void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) { if (!ptr) return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false)); + +#if HWASAN_WITH_INTERCEPTORS + // A tag of 0 means that this is a system allocator allocation, so we must use + // the system allocator to realloc it. + if (!flags()->disable_allocator_tagging && GetTagFromPointer((uptr)ptr) == 0) + return REAL(realloc)(ptr, size); +#endif + if (size == 0) { HwasanDeallocate(stack, ptr); return nullptr; @@ -376,6 +389,17 @@ return 0; } +void hwasan_free(void *ptr, StackTrace *stack) { +#if HWASAN_WITH_INTERCEPTORS + // A tag of 0 means that this is a system allocator allocation, so we must use + // the system allocator to free it. + if (!flags()->disable_allocator_tagging && GetTagFromPointer((uptr)ptr) == 0) + return REAL(free)(ptr); +#endif + + return HwasanDeallocate(stack, ptr); +} + } // namespace __hwasan using namespace __hwasan; @@ -385,6 +409,15 @@ } void __hwasan_disable_allocator_tagging() { +#if HWASAN_WITH_INTERCEPTORS + // Allocator tagging must be enabled for the system allocator fallback to work + // correctly. This means that we can't disable it at runtime if it was enabled + // at startup since that might result in our deallocations going to the system + // allocator. If tagging was disabled at startup we avoid this problem by + // disabling the fallback altogether. + CHECK(flags()->disable_allocator_tagging); +#endif + atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 0); } Index: compiler-rt/trunk/lib/hwasan/hwasan_interceptors.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_interceptors.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_interceptors.cc @@ -17,6 +17,7 @@ #include "interception/interception.h" #include "hwasan.h" +#include "hwasan_allocator.h" #include "hwasan_mapping.h" #include "hwasan_thread.h" #include "hwasan_poisoning.h" @@ -44,11 +45,6 @@ using __sanitizer::atomic_store; using __sanitizer::atomic_uintptr_t; -DECLARE_REAL(SIZE_T, strlen, const char *s) -DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen) -DECLARE_REAL(void *, memcpy, void *dest, const void *src, uptr n) -DECLARE_REAL(void *, memset, void *dest, int c, uptr n) - bool IsInInterceptorScope() { Thread *t = GetCurrentThread(); return t && t->InInterceptorScope(); @@ -130,13 +126,13 @@ void __sanitizer_free(void *ptr) { GET_MALLOC_STACK_TRACE; if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return; - HwasanDeallocate(&stack, ptr); + hwasan_free(ptr, &stack); } void __sanitizer_cfree(void *ptr) { GET_MALLOC_STACK_TRACE; if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) return; - HwasanDeallocate(&stack, ptr); + hwasan_free(ptr, &stack); } uptr __sanitizer_malloc_usable_size(const void *ptr) { @@ -290,6 +286,8 @@ #if HWASAN_WITH_INTERCEPTORS INTERCEPT_FUNCTION(pthread_create); + INTERCEPT_FUNCTION(realloc); + INTERCEPT_FUNCTION(free); #endif inited = 1; Index: compiler-rt/trunk/lib/hwasan/hwasan_linux.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_linux.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_linux.cc @@ -40,6 +40,7 @@ #include "sanitizer_common/sanitizer_procmaps.h" #if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID +SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL uptr __hwasan_tls; #endif Index: compiler-rt/trunk/lib/hwasan/hwasan_new_delete.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_new_delete.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_new_delete.cc @@ -51,7 +51,7 @@ #define OPERATOR_DELETE_BODY \ GET_MALLOC_STACK_TRACE; \ - if (ptr) HwasanDeallocate(&stack, ptr) + if (ptr) hwasan_free(ptr, &stack) INTERCEPTOR_ATTRIBUTE void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } Index: compiler-rt/trunk/test/hwasan/TestCases/Posix/system-allocator-fallback.cc =================================================================== --- compiler-rt/trunk/test/hwasan/TestCases/Posix/system-allocator-fallback.cc +++ compiler-rt/trunk/test/hwasan/TestCases/Posix/system-allocator-fallback.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx %s -o %t -ldl +// RUN: %clangxx_hwasan -shared %s -o %t.so -DSHARED_LIB -shared-libsan -Wl,-rpath,%compiler_rt_libdir +// RUN: %env_hwasan_opts=disable_allocator_tagging=0 %run %t + +#include + +// Test that allocations made by the system allocator can be realloc'd and freed +// by the hwasan allocator. + +typedef void run_test_fn(void *(*system_malloc)(size_t size)); + +#ifdef SHARED_LIB + +// Call the __sanitizer_ versions of these functions so that the test +// doesn't require the Android dynamic loader. +extern "C" void *__sanitizer_realloc(void *ptr, size_t size); +extern "C" void __sanitizer_free(void *ptr); + +extern "C" run_test_fn run_test; +void run_test(void *(*system_malloc)(size_t size)) { + void *mem = system_malloc(64); + mem = __sanitizer_realloc(mem, 128); + __sanitizer_free(mem); +} + +#else + +#include +#include +#include + +int main(int argc, char **argv) { + std::string path = argv[0]; + path += ".so"; + void *lib = dlopen(path.c_str(), RTLD_NOW); + if (!lib) { + printf("error in dlopen(): %s\n", dlerror()); + return 1; + } + + auto run_test = reinterpret_cast(dlsym(lib, "run_test")); + if (!run_test) { + printf("failed dlsym\n"); + return 1; + } + + run_test(malloc); +} + +#endif Index: compiler-rt/trunk/test/hwasan/lit.cfg =================================================================== --- compiler-rt/trunk/test/hwasan/lit.cfg +++ compiler-rt/trunk/test/hwasan/lit.cfg @@ -9,14 +9,18 @@ config.test_source_root = os.path.dirname(__file__) # Setup default compiler flags used with -fsanitize=memory option. -clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls", config.target_cflags] + config.debug_info_flags +clang_cflags = [config.target_cflags] + config.debug_info_flags +clang_cxxflags = config.cxx_mode_flags + clang_cflags +clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls"] + clang_cflags clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " +config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_hwasan ", build_invocation(clang_hwasan_cflags)) ) config.substitutions.append( ("%clangxx_hwasan ", build_invocation(clang_hwasan_cxxflags)) ) +config.substitutions.append( ("%compiler_rt_libdir", config.compiler_rt_libdir) ) default_hwasan_opts_str = ':'.join(['disable_allocator_tagging=1', 'random_tags=0'] + config.default_sanitizer_opts) if default_hwasan_opts_str: