diff --git a/compiler-rt/lib/dfsan/CMakeLists.txt b/compiler-rt/lib/dfsan/CMakeLists.txt --- a/compiler-rt/lib/dfsan/CMakeLists.txt +++ b/compiler-rt/lib/dfsan/CMakeLists.txt @@ -7,6 +7,7 @@ dfsan_chained_origin_depot.cpp dfsan_custom.cpp dfsan_interceptors.cpp + dfsan_new_delete.cpp dfsan_thread.cpp ) diff --git a/compiler-rt/lib/dfsan/dfsan.h b/compiler-rt/lib/dfsan/dfsan.h --- a/compiler-rt/lib/dfsan/dfsan.h +++ b/compiler-rt/lib/dfsan/dfsan.h @@ -65,7 +65,7 @@ extern bool dfsan_inited; extern bool dfsan_init_is_running; -void InitializeInterceptors(); +void initialize_interceptors(); inline dfsan_label *shadow_for(void *ptr) { return (dfsan_label *) ((((uptr) ptr) & ShadowMask()) << 1); diff --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp --- a/compiler-rt/lib/dfsan/dfsan.cpp +++ b/compiler-rt/lib/dfsan/dfsan.cpp @@ -1113,7 +1113,7 @@ if (!(init_addr >= UnusedAddr() && init_addr < AppAddr())) MmapFixedNoAccess(UnusedAddr(), AppAddr() - UnusedAddr()); - InitializeInterceptors(); + initialize_interceptors(); // Register the fini callback to run when the program terminates successfully // or it is killed by the runtime. diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp --- a/compiler-rt/lib/dfsan/dfsan_custom.cpp +++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp @@ -461,24 +461,6 @@ return r; } -SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size, - dfsan_label nmemb_label, - dfsan_label size_label, - dfsan_label *ret_label) { - void *p = calloc(nmemb, size); - dfsan_set_label(0, p, nmemb * size); - *ret_label = 0; - return p; -} - -SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_calloc( - size_t nmemb, size_t size, dfsan_label nmemb_label, dfsan_label size_label, - dfsan_label *ret_label, dfsan_origin nmemb_origin, dfsan_origin size_origin, - dfsan_origin *ret_origin) { - void *p = __dfsw_calloc(nmemb, size, nmemb_label, size_label, ret_label); - *ret_origin = 0; - return p; -} SANITIZER_INTERFACE_ATTRIBUTE size_t __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) { diff --git a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp --- a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp +++ b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp @@ -15,8 +15,14 @@ #include #include "dfsan/dfsan.h" +#include "dfsan/dfsan_thread.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_errno.h" +#include "sanitizer_common/sanitizer_platform_limits_posix.h" +#include "sanitizer_common/sanitizer_posix.h" +#include "sanitizer_common/sanitizer_tls_get_addr.h" using namespace __sanitizer; @@ -26,44 +32,213 @@ } // namespace -INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, - int fd, OFF_T offset) { - void *res; +INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) { + return __dfsan::dfsan_reallocarray(ptr, nmemb, size); +} + +INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) { + void *ptr = __dfsan::dfsan_memalign(alignment, size); + if (ptr) + DTLS_on_libc_memalign(ptr, size); + return ptr; +} + +INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { + return __dfsan::dfsan_aligned_alloc(alignment, size); +} + +static uptr allocated_for_dlsym; +static const uptr kDlsymAllocPoolSize = 1024; +static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; + +static bool IsInDlsymAllocPool(const void *ptr) { + uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; + return off < sizeof(alloc_memory_for_dlsym); +} + +static void *AllocateFromLocalPool(uptr size_in_bytes) { + uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; + void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym]; + allocated_for_dlsym += size_in_words; + CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); + return mem; +} + +INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { + if (UNLIKELY(!__dfsan::dfsan_inited)) + // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. + return AllocateFromLocalPool(nmemb * size); + return __dfsan::dfsan_calloc(nmemb, size); +} + +INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { + if (UNLIKELY(IsInDlsymAllocPool(ptr))) { + uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; + uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); + void *new_ptr; + if (UNLIKELY(!__dfsan::dfsan_inited)) { + new_ptr = AllocateFromLocalPool(copy_size); + } else { + copy_size = size; + new_ptr = __dfsan::dfsan_malloc(copy_size); + } + internal_memcpy(new_ptr, ptr, copy_size); + return new_ptr; + } + return __dfsan::dfsan_realloc(ptr, size); +} + +INTERCEPTOR(void *, malloc, SIZE_T size) { + if (UNLIKELY(!__dfsan::dfsan_inited)) + // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. + return AllocateFromLocalPool(size); + return __dfsan::dfsan_malloc(size); +} + +INTERCEPTOR(void, free, void *ptr) { + if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) + return; + return __dfsan::dfsan_deallocate(ptr); +} + +INTERCEPTOR(void, cfree, void *ptr) { + if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) + return; + return __dfsan::dfsan_deallocate(ptr); +} - // interceptors_initialized is set to true during preinit_array, when we're - // single-threaded. So we don't need to worry about accessing it atomically. - if (!interceptors_initialized) - res = (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset); - else - res = REAL(mmap)(addr, length, prot, flags, fd, offset); +INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { + CHECK_NE(memptr, 0); + int res = __dfsan::dfsan_posix_memalign(memptr, alignment, size); + if (!res) + dfsan_set_label(0, memptr, sizeof(*memptr)); + return res; +} + +INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) { + return __dfsan::dfsan_memalign(alignment, size); +} + +INTERCEPTOR(void *, valloc, SIZE_T size) { return __dfsan::dfsan_valloc(size); } + +INTERCEPTOR(void *, pvalloc, SIZE_T size) { + return __dfsan::dfsan_pvalloc(size); +} + +INTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) { + internal_memset(sret, 0, sizeof(*sret)); + dfsan_set_label(0, sret, sizeof(*sret)); +} + +INTERCEPTOR(int, mallopt, int cmd, int value) { return 0; } + +INTERCEPTOR(void, malloc_stats, void) { + // FIXME: implement, but don't call REAL(malloc_stats)! +} + +INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { + return __sanitizer_get_allocated_size(ptr); +} - if (res != (void *)-1) +#define ENSURE_DFSAN_INITED() \ + do { \ + CHECK(!__dfsan::dfsan_init_is_running); \ + if (!__dfsan::dfsan_inited) { \ + __dfsan::dfsan_init(); \ + } \ + } while (0) + +#define COMMON_INTERCEPTOR_ENTER(func, ...) \ + if (__dfsan::dfsan_init_is_running) \ + return REAL(func)(__VA_ARGS__); \ + ENSURE_DFSAN_INITED(); \ + dfsan_set_label(0, __errno_location(), sizeof(int)); /* NOLINT */ + +INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, + int fd, OFF_T offset) { + if (common_flags()->detect_write_exec) + ReportMmapWriteExec(prot); + if (!__dfsan::dfsan_inited) + return (void *)internal_mmap(addr, length, prot, flags, fd, offset); + COMMON_INTERCEPTOR_ENTER(mmap, addr, length, prot, flags, fd, offset); + void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); + if (res != (void *)-1) { dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); + } return res; } INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { + if (common_flags()->detect_write_exec) + ReportMmapWriteExec(prot); + if (!__dfsan::dfsan_inited) + return (void *)internal_mmap(addr, length, prot, flags, fd, offset); + COMMON_INTERCEPTOR_ENTER(mmap64, addr, length, prot, flags, fd, offset); void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); - if (res != (void *)-1) + if (res != (void *)-1) { dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); + } return res; } INTERCEPTOR(int, munmap, void *addr, SIZE_T length) { + if (!__dfsan::dfsan_inited) + return internal_munmap(addr, length); + COMMON_INTERCEPTOR_ENTER(munmap, addr, length); int res = REAL(munmap)(addr, length); if (res != -1) dfsan_set_label(0, addr, RoundUpTo(length, GetPageSizeCached())); return res; } +#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ + if (__dfsan::DFsanThread *t = __dfsan::GetCurrentThread()) { \ + *begin = t->tls_begin(); \ + *end = t->tls_end(); \ + } else { \ + *begin = *end = 0; \ + } +#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \ + dfsan_set_label(0, ptr, size) + +INTERCEPTOR(void *, __tls_get_addr, void *arg) { + COMMON_INTERCEPTOR_ENTER(__tls_get_addr, arg); + void *res = REAL(__tls_get_addr)(arg); + uptr tls_begin, tls_end; + COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end); + if (dtv) { + // New DTLS block has been allocated. + COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); + } + return res; +} + namespace __dfsan { -void InitializeInterceptors() { +void initialize_interceptors() { CHECK(!interceptors_initialized); + INTERCEPT_FUNCTION(aligned_alloc); + INTERCEPT_FUNCTION(calloc); + INTERCEPT_FUNCTION(cfree); + INTERCEPT_FUNCTION(free); + INTERCEPT_FUNCTION(mallinfo); + INTERCEPT_FUNCTION(malloc); + INTERCEPT_FUNCTION(malloc_stats); + INTERCEPT_FUNCTION(malloc_usable_size); + INTERCEPT_FUNCTION(mallopt); + INTERCEPT_FUNCTION(memalign); INTERCEPT_FUNCTION(mmap); INTERCEPT_FUNCTION(mmap64); INTERCEPT_FUNCTION(munmap); + INTERCEPT_FUNCTION(posix_memalign); + INTERCEPT_FUNCTION(pvalloc); + INTERCEPT_FUNCTION(realloc); + INTERCEPT_FUNCTION(reallocarray); + INTERCEPT_FUNCTION(valloc); + INTERCEPT_FUNCTION(__tls_get_addr); + INTERCEPT_FUNCTION(__libc_memalign); interceptors_initialized = true; } diff --git a/compiler-rt/lib/dfsan/dfsan_new_delete.cpp b/compiler-rt/lib/dfsan/dfsan_new_delete.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/dfsan/dfsan_new_delete.cpp @@ -0,0 +1,124 @@ +//===-- dfsan_new_delete.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of DataflowSanitizer. +// +// Interceptors for operators new and delete. +//===----------------------------------------------------------------------===// + +#include + +#include "dfsan.h" +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h" + +using namespace __dfsan; + +// Fake std::nothrow_t and std::align_val_t to avoid including . +namespace std { +struct nothrow_t {}; +enum class align_val_t : size_t {}; +} // namespace std + +// TODO(alekseys): throw std::bad_alloc instead of dying on OOM. +#define OPERATOR_NEW_BODY(nothrow) \ + void *res = dfsan_malloc(size); \ + if (!nothrow && UNLIKELY(!res)) { \ + BufferedStackTrace stack; \ + ReportOutOfMemory(size, &stack); \ + } \ + return res +#define OPERATOR_NEW_BODY_ALIGN(nothrow) \ + void *res = dfsan_memalign((uptr)align, size); \ + if (!nothrow && UNLIKELY(!res)) { \ + BufferedStackTrace stack; \ + ReportOutOfMemory(size, &stack); \ + } \ + return res; + +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); } +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::nothrow_t const &) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::nothrow_t const &) { + OPERATOR_NEW_BODY(true /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align) { + OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align) { + OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new(size_t size, std::align_val_t align, + std::nothrow_t const &) { + OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); +} +INTERCEPTOR_ATTRIBUTE +void *operator new[](size_t size, std::align_val_t align, + std::nothrow_t const &) { + OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); +} + +#define OPERATOR_DELETE_BODY \ + if (ptr) \ + dfsan_deallocate(ptr) + +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr)NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::nothrow_t const &) { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::nothrow_t const &) { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size)NOEXCEPT { OPERATOR_DELETE_BODY; } +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size) NOEXCEPT { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align)NOEXCEPT { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, + std::nothrow_t const &) { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, + std::nothrow_t const &) { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete(void *ptr, size_t size, std::align_val_t align)NOEXCEPT { + OPERATOR_DELETE_BODY; +} +INTERCEPTOR_ATTRIBUTE +void operator delete[](void *ptr, size_t size, + std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY; +} diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt --- a/compiler-rt/lib/dfsan/done_abilist.txt +++ b/compiler-rt/lib/dfsan/done_abilist.txt @@ -41,8 +41,23 @@ ############################################################################### # glibc ############################################################################### +# Functions of memory allocators +fun:__libc_memalign=discard +fun:aligned_alloc=discard +fun:calloc=discard +fun:cfree=discard +fun:mallinfo=discard fun:malloc=discard fun:free=discard +fun:malloc_stats=discard +fun:malloc_usable_size=discard +fun:mallopt=discard +fun:memalign=discard +fun:posix_memalign=discard +fun:pvalloc=discard +fun:realloc=discard +fun:reallocarray=discard +fun:valloc=discard # Functions that return a value that depends on the input, but the output might # not be necessarily data-dependent on the input. @@ -157,7 +172,6 @@ fun:openat=discard fun:pipe=discard fun:posix_fadvise=discard -fun:posix_memalign=discard fun:prctl=discard fun:printf=discard fun:pthread_sigmask=discard @@ -193,7 +207,6 @@ # Functions that produce output does not depend on the input (need to zero the # shadow manually). fun:_dl_get_tls_static_info=custom -fun:calloc=custom fun:clock_gettime=custom fun:dlopen=custom fun:epoll_wait=custom @@ -401,6 +414,36 @@ fun:__sanitizer_cov_pcs_init=uninstrumented fun:__sanitizer_cov_pcs_init=discard +fun:__sanitizer_get_current_allocated_bytes=uninstrumented +fun:__sanitizer_get_current_allocated_bytes=discard +fun:__sanitizer_get_heap_size=uninstrumented +fun:__sanitizer_get_heap_size=discard +fun:__sanitizer_get_free_bytes=uninstrumented +fun:__sanitizer_get_free_bytes=discard +fun:__sanitizer_get_unmapped_bytes=uninstrumented +fun:__sanitizer_get_unmapped_bytes=discard +fun:__sanitizer_get_estimated_allocated_size=uninstrumented +fun:__sanitizer_get_estimated_allocated_size=discard +fun:__sanitizer_get_ownership=uninstrumented +fun:__sanitizer_get_ownership=discard +fun:__sanitizer_get_allocated_size=uninstrumented +fun:__sanitizer_get_allocated_size=discard +fun:__sanitizer_print_stack_trace=uninstrumented +fun:__sanitizer_print_stack_trace=discard + +fun:TcmallocSlab_Internal_PushBatch_FixedShift=uninstrumented +fun:TcmallocSlab_Internal_PushBatch_FixedShift=discard +fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=uninstrumented +fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=discard +fun:TcmallocSlab_Internal_PerCpuCmpxchg64=uninstrumented +fun:TcmallocSlab_Internal_PerCpuCmpxchg64=discard +fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=uninstrumented +fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=discard +fun:TcmallocSlab_Internal_PopBatch_FixedShift=uninstrumented +fun:TcmallocSlab_Internal_PopBatch_FixedShift=discard +fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=uninstrumented +fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=discard + # Ignores the dfsan wrappers. fun:__dfsw_*=uninstrumented fun:__dfsw_*=discard diff --git a/compiler-rt/test/dfsan/custom.cpp b/compiler-rt/test/dfsan/custom.cpp --- a/compiler-rt/test/dfsan/custom.cpp +++ b/compiler-rt/test/dfsan/custom.cpp @@ -603,20 +603,6 @@ #endif } -void test_calloc() { - // With any luck this sequence of calls will cause calloc to return the same - // pointer both times. This is probably the best we can do to test this - // function. - char *crv = (char *) calloc(4096, 1); - ASSERT_ZERO_LABEL(crv[0]); - dfsan_set_label(i_label, crv, 100); - free(crv); - - crv = (char *) calloc(4096, 1); - ASSERT_ZERO_LABEL(crv[0]); - free(crv); -} - void test_recvmmsg() { int sockfds[2]; int ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sockfds); @@ -1935,7 +1921,6 @@ test__dl_get_tls_static_info(); test_bcmp(); - test_calloc(); test_clock_gettime(); test_ctime_r(); test_dfsan_set_write_callback(); diff --git a/compiler-rt/test/dfsan/interceptors.c b/compiler-rt/test/dfsan/interceptors.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/dfsan/interceptors.c @@ -0,0 +1,191 @@ +// RUN: %clang_dfsan -mllvm -dfsan-fast-16-labels -mllvm -dfsan-combine-pointer-labels-on-load=false %s -o %t && %run %t +// RUN: %clang_dfsan -DORIGIN_TRACKING -mllvm -dfsan-fast-16-labels -mllvm -dfsan-track-origins=1 -mllvm -dfsan-combine-pointer-labels-on-load=false %s -o %t && %run %t +// +// Tests custom implementations of various glibc functions. +// +// REQUIRES: x86_64-target-arch + +#include + +#include +#include +#include +#include + +#define ASSERT_ZERO_LABEL(data) \ + assert(0 == dfsan_get_label((long) (data))) + +#define ASSERT_READ_ZERO_LABEL(ptr, size) \ + assert(0 == dfsan_read_label(ptr, size)) + +const int kAlignment = 8; +const int kSize = 16; + +void test_aligned_alloc() { + char *p = (char *) aligned_alloc(kAlignment, kSize); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test_calloc() { + char *p = (char *) calloc(kSize, 1); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test_cfree() { + // The current glibc does not support cfree. +} + +void test_free() { + char *p = (char *) malloc(kSize); + dfsan_set_label(1, p, kSize); + free(p); + ASSERT_READ_ZERO_LABEL(p, kSize); +} + +void test_mallinfo() { + struct mallinfo mi = mallinfo(); + for (int i = 0; i < sizeof(struct mallinfo); ++i) { + char c = ((char *)(&mi))[i]; + assert(!c); + ASSERT_ZERO_LABEL(c); + } +} + +void test_malloc() { + char *p = (char *) malloc(kSize); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test_malloc_stats() { + // Only ensures it does not crash. Our interceptor of malloc_stats is empty. + malloc_stats(); +} + +void test_malloc_usable_size() { + char *p = (char *) malloc(kSize); + size_t s = malloc_usable_size(p); + assert(s == kSize); + ASSERT_ZERO_LABEL(s); + free(p); +} + +void test_mallopt() { + int r = mallopt(0, 0); + assert(!r); + ASSERT_ZERO_LABEL(r); +} + +void test_memalign() { + char *p = (char *) memalign(kAlignment, kSize); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test_mmap() { + char *p = mmap(NULL, kSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_READ_ZERO_LABEL(p, kSize); + char val = 0xff; + dfsan_set_label(1, &val, sizeof(val)); + memset(p, val, kSize); + p = mmap(p, kSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ASSERT_READ_ZERO_LABEL(p, kSize); + munmap(p, kSize); +} + +void test_mmap64() { + // The current glibc does not support mmap64. +} + +void test_unmmap() { + char *p = mmap(NULL, kSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + char val = 0xff; + dfsan_set_label(1, &val, sizeof(val)); + memset(p, val, kSize); + munmap(p, kSize); + ASSERT_READ_ZERO_LABEL(p, kSize); +} + +void test_posix_memalign() { + char *p; + dfsan_set_label(1, &p, sizeof(p)); + int r = posix_memalign((void **)&p, kAlignment, kSize); + assert(!r); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test_pvalloc() { + char *p = (char *) pvalloc(kSize); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test_realloc() { + char *p = (char *) malloc(kSize); + + char *q = (char *) realloc(p, kSize * 2); + ASSERT_ZERO_LABEL(q); + ASSERT_READ_ZERO_LABEL(q, kSize * 2); + + char *x = (char *) realloc(q, kSize); + ASSERT_ZERO_LABEL(x); + ASSERT_READ_ZERO_LABEL(x, kSize); + + free(x); +} + +void test_reallocarray() { + // The current glibc does not support reallocarray. +} + +void test_valloc() { + char *p = (char *) valloc(kSize); + ASSERT_ZERO_LABEL(p); + ASSERT_READ_ZERO_LABEL(p, kSize); + free(p); +} + +void test___libc_memalign() { + // The current glibc does not support __libc_memalign. +} + +void test___tls_get_addr() { + // The current glibc does not support __tls_get_addr. +} + +int main(void) { + // With any luck this sequence of calls will cause allocators to return the + // same pointer. This is probably the best we can do to test these functions. + test_aligned_alloc(); + test_calloc(); + test_cfree(); + test_free(); + test_mallinfo(); + test_malloc(); + test_malloc_stats(); + test_malloc_usable_size(); + test_mallopt(); + test_memalign(); + test_mmap(); + test_mmap64(); + test_unmmap(); + test_posix_memalign(); + test_pvalloc(); + test_realloc(); + test_reallocarray(); + test_valloc(); + test___libc_memalign(); + test___tls_get_addr(); +}