aboutsummaryrefslogtreecommitdiff
path: root/libsanitizer/asan
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2023-04-26 09:42:29 +0200
committerMartin Liska <mliska@suse.cz>2023-04-26 15:51:56 +0200
commitd53b3d94aaf211ffb2159614f5aaaf03ceb861cc (patch)
tree4202fe134ccc618029a07e7d1913c608bd7fb77f /libsanitizer/asan
parenta8e1551bdb372aa3cfe754429b5efd6229ae5fdb (diff)
downloadgcc-d53b3d94aaf211ffb2159614f5aaaf03ceb861cc.zip
gcc-d53b3d94aaf211ffb2159614f5aaaf03ceb861cc.tar.gz
gcc-d53b3d94aaf211ffb2159614f5aaaf03ceb861cc.tar.bz2
libsanitizer: merge from upstream (3185e47b5a8444e9fd).
Diffstat (limited to 'libsanitizer/asan')
-rw-r--r--libsanitizer/asan/asan_allocator.cpp50
-rw-r--r--libsanitizer/asan/asan_allocator.h8
-rw-r--r--libsanitizer/asan/asan_errors.cpp20
-rw-r--r--libsanitizer/asan/asan_errors.h67
-rw-r--r--libsanitizer/asan/asan_globals.cpp19
-rw-r--r--libsanitizer/asan/asan_interceptors.cpp59
-rw-r--r--libsanitizer/asan/asan_interceptors.h7
-rw-r--r--libsanitizer/asan/asan_internal.h2
-rw-r--r--libsanitizer/asan/asan_linux.cpp164
-rw-r--r--libsanitizer/asan/asan_mac.cpp6
-rw-r--r--libsanitizer/asan/asan_malloc_win.cpp8
-rw-r--r--libsanitizer/asan/asan_mapping.h2
-rw-r--r--libsanitizer/asan/asan_memory_profile.cpp19
-rw-r--r--libsanitizer/asan/asan_poisoning.cpp334
-rw-r--r--libsanitizer/asan/asan_report.cpp12
-rw-r--r--libsanitizer/asan/asan_report.h4
-rw-r--r--libsanitizer/asan/asan_thread.cpp86
-rw-r--r--libsanitizer/asan/asan_win.cpp6
18 files changed, 584 insertions, 289 deletions
diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
index 52d7eff..19d7777 100644
--- a/libsanitizer/asan/asan_allocator.cpp
+++ b/libsanitizer/asan/asan_allocator.cpp
@@ -1094,10 +1094,16 @@ uptr PointsIntoChunk(void *p) {
}
uptr GetUserBegin(uptr chunk) {
+ // FIXME: All usecases provide chunk address, GetAsanChunkByAddrFastLocked is
+ // not needed.
__asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
return m ? m->Beg() : 0;
}
+uptr GetUserAddr(uptr chunk) {
+ return chunk;
+}
+
LsanMetadata::LsanMetadata(uptr chunk) {
metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize)
: nullptr;
@@ -1138,7 +1144,7 @@ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
__asan::get_allocator().ForEachChunk(callback, arg);
}
-IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+IgnoreObjectResult IgnoreObject(const void *p) {
uptr addr = reinterpret_cast<uptr>(p);
__asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr);
if (!m ||
@@ -1153,38 +1159,22 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
return kIgnoreObjectSuccess;
}
-void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
- // Look for the arg pointer of threads that have been created or are running.
- // This is necessary to prevent false positive leaks due to the AsanThread
- // holding the only live reference to a heap object. This can happen because
- // the `pthread_create()` interceptor doesn't wait for the child thread to
- // start before returning and thus loosing the the only live reference to the
- // heap object on the stack.
-
- __asan::AsanThreadContext *atctx =
- reinterpret_cast<__asan::AsanThreadContext *>(tctx);
- __asan::AsanThread *asan_thread = atctx->thread;
-
- // Note ThreadStatusRunning is required because there is a small window where
- // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
- // still isn't on the stack yet.
- if (atctx->status != ThreadStatusCreated &&
- atctx->status != ThreadStatusRunning)
- return;
-
- uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
- if (!thread_arg)
- return;
-
- auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
- ptrsVec->push_back(thread_arg);
-}
-
} // namespace __lsan
// ---------------------- Interface ---------------- {{{1
using namespace __asan;
+static const void *AllocationBegin(const void *p) {
+ AsanChunk *m = __asan::instance.GetAsanChunkByAddr((uptr)p);
+ if (!m)
+ return nullptr;
+ if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
+ return nullptr;
+ if (m->UsedSize() == 0)
+ return nullptr;
+ return (const void *)(m->Beg());
+}
+
// ASan allocator doesn't reserve extra bytes, so normally we would
// just return "size". We don't want to expose our redzone sizes, etc here.
uptr __sanitizer_get_estimated_allocated_size(uptr size) {
@@ -1208,6 +1198,10 @@ uptr __sanitizer_get_allocated_size(const void *p) {
return allocated_size;
}
+const void *__sanitizer_get_allocated_begin(const void *p) {
+ return AllocationBegin(p);
+}
+
void __sanitizer_purge_allocator() {
GET_STACK_TRACE_MALLOC;
instance.Purge(&stack);
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index 0b4dbf0..6a12a6c 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -143,11 +143,15 @@ typedef DefaultSizeClassMap SizeClassMap;
const uptr kAllocatorSpace = ~(uptr)0;
const uptr kAllocatorSize = 0x8000000000ULL; // 500G
typedef DefaultSizeClassMap SizeClassMap;
-# else
+# elif SANITIZER_APPLE
const uptr kAllocatorSpace = 0x600000000000ULL;
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
typedef DefaultSizeClassMap SizeClassMap;
-# endif
+# else
+const uptr kAllocatorSpace = 0x500000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+typedef DefaultSizeClassMap SizeClassMap;
+# endif
template <typename AddressSpaceViewTy>
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = kAllocatorSpace;
diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
index f3befdf..cc8dc26 100644
--- a/libsanitizer/asan/asan_errors.cpp
+++ b/libsanitizer/asan/asan_errors.cpp
@@ -334,6 +334,26 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() {
ReportErrorSummary(scariness.GetDescription(), stack);
}
+void ErrorBadParamsToAnnotateDoubleEndedContiguousContainer::Print() {
+ Report(
+ "ERROR: AddressSanitizer: bad parameters to "
+ "__sanitizer_annotate_double_ended_contiguous_container:\n"
+ " storage_beg : %p\n"
+ " storage_end : %p\n"
+ " old_container_beg : %p\n"
+ " old_container_end : %p\n"
+ " new_container_beg : %p\n"
+ " new_container_end : %p\n",
+ (void *)storage_beg, (void *)storage_end, (void *)old_container_beg,
+ (void *)old_container_end, (void *)new_container_beg,
+ (void *)new_container_end);
+ uptr granularity = ASAN_SHADOW_GRANULARITY;
+ if (!IsAligned(storage_beg, granularity))
+ Report("ERROR: storage_beg is not aligned by %zu\n", granularity);
+ stack->Print();
+ ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
void ErrorODRViolation::Print() {
Decorator d;
Printf("%s", d.Error());
diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h
index c6ac88f..634f6da 100644
--- a/libsanitizer/asan/asan_errors.h
+++ b/libsanitizer/asan/asan_errors.h
@@ -331,6 +331,28 @@ struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
void Print();
};
+struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase {
+ const BufferedStackTrace *stack;
+ uptr storage_beg, storage_end, old_container_beg, old_container_end,
+ new_container_beg, new_container_end;
+
+ ErrorBadParamsToAnnotateDoubleEndedContiguousContainer() = default; // (*)
+ ErrorBadParamsToAnnotateDoubleEndedContiguousContainer(
+ u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_,
+ uptr old_container_beg_, uptr old_container_end_, uptr new_container_beg_,
+ uptr new_container_end_)
+ : ErrorBase(tid, 10,
+ "bad-__sanitizer_annotate_double_ended_contiguous_container"),
+ stack(stack_),
+ storage_beg(storage_beg_),
+ storage_end(storage_end_),
+ old_container_beg(old_container_beg_),
+ old_container_end(old_container_end_),
+ new_container_beg(new_container_beg_),
+ new_container_end(new_container_end_) {}
+ void Print();
+};
+
struct ErrorODRViolation : ErrorBase {
__asan_global global1, global2;
u32 stack_id1, stack_id2;
@@ -378,28 +400,29 @@ struct ErrorGeneric : ErrorBase {
};
// clang-format off
-#define ASAN_FOR_EACH_ERROR_KIND(macro) \
- macro(DeadlySignal) \
- macro(DoubleFree) \
- macro(NewDeleteTypeMismatch) \
- macro(FreeNotMalloced) \
- macro(AllocTypeMismatch) \
- macro(MallocUsableSizeNotOwned) \
- macro(SanitizerGetAllocatedSizeNotOwned) \
- macro(CallocOverflow) \
- macro(ReallocArrayOverflow) \
- macro(PvallocOverflow) \
- macro(InvalidAllocationAlignment) \
- macro(InvalidAlignedAllocAlignment) \
- macro(InvalidPosixMemalignAlignment) \
- macro(AllocationSizeTooBig) \
- macro(RssLimitExceeded) \
- macro(OutOfMemory) \
- macro(StringFunctionMemoryRangesOverlap) \
- macro(StringFunctionSizeOverflow) \
- macro(BadParamsToAnnotateContiguousContainer) \
- macro(ODRViolation) \
- macro(InvalidPointerPair) \
+#define ASAN_FOR_EACH_ERROR_KIND(macro) \
+ macro(DeadlySignal) \
+ macro(DoubleFree) \
+ macro(NewDeleteTypeMismatch) \
+ macro(FreeNotMalloced) \
+ macro(AllocTypeMismatch) \
+ macro(MallocUsableSizeNotOwned) \
+ macro(SanitizerGetAllocatedSizeNotOwned) \
+ macro(CallocOverflow) \
+ macro(ReallocArrayOverflow) \
+ macro(PvallocOverflow) \
+ macro(InvalidAllocationAlignment) \
+ macro(InvalidAlignedAllocAlignment) \
+ macro(InvalidPosixMemalignAlignment) \
+ macro(AllocationSizeTooBig) \
+ macro(RssLimitExceeded) \
+ macro(OutOfMemory) \
+ macro(StringFunctionMemoryRangesOverlap) \
+ macro(StringFunctionSizeOverflow) \
+ macro(BadParamsToAnnotateContiguousContainer) \
+ macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \
+ macro(ODRViolation) \
+ macro(InvalidPointerPair) \
macro(Generic)
// clang-format on
diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
index 01a2439..4d391cb 100644
--- a/libsanitizer/asan/asan_globals.cpp
+++ b/libsanitizer/asan/asan_globals.cpp
@@ -158,6 +158,23 @@ static void CheckODRViolationViaIndicator(const Global *g) {
}
}
+// Check ODR violation for given global G by checking if it's already poisoned.
+// We use this method in case compiler doesn't use private aliases for global
+// variables.
+static void CheckODRViolationViaPoisoning(const Global *g) {
+ if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) {
+ // This check may not be enough: if the first global is much larger
+ // the entire redzone of the second global may be within the first global.
+ for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
+ if (g->beg == l->g->beg &&
+ (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
+ !IsODRViolationSuppressed(g->name))
+ ReportODRViolation(g, FindRegistrationSite(g),
+ l->g, FindRegistrationSite(l->g));
+ }
+ }
+}
+
// Clang provides two different ways for global variables protection:
// it can poison the global itself or its private alias. In former
// case we may poison same symbol multiple times, that can help us to
@@ -203,6 +220,8 @@ static void RegisterGlobal(const Global *g) {
// where two globals with the same name are defined in different modules.
if (UseODRIndicator(g))
CheckODRViolationViaIndicator(g);
+ else
+ CheckODRViolationViaPoisoning(g);
}
if (CanPoisonMemory())
PoisonRedZones(*g);
diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp
index 8170082..0f16005 100644
--- a/libsanitizer/asan/asan_interceptors.cpp
+++ b/libsanitizer/asan/asan_interceptors.cpp
@@ -257,12 +257,36 @@ static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
PoisonShadow(bottom, ssize, 0);
}
-INTERCEPTOR(int, getcontext, struct ucontext_t *ucp) {
- // API does not requires to have ucp clean, and sets only part of fields. We
- // use ucp->uc_stack to unpoison new stack. We prefer to have zeroes then
- // uninitialized bytes.
- ResetContextStack(ucp);
- return REAL(getcontext)(ucp);
+INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
+ ...) {
+ va_list ap;
+ uptr args[64];
+ // We don't know a better way to forward ... into REAL function. We can
+ // increase args size if neccecary.
+ CHECK_LE(argc, ARRAY_SIZE(args));
+ internal_memset(args, 0, sizeof(args));
+ va_start(ap, argc);
+ for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
+ va_end(ap);
+
+# define ENUMERATE_ARRAY_4(start) \
+ args[start], args[start + 1], args[start + 2], args[start + 3]
+# define ENUMERATE_ARRAY_16(start) \
+ ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
+ ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
+# define ENUMERATE_ARRAY_64() \
+ ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
+ ENUMERATE_ARRAY_16(48)
+
+ REAL(makecontext)
+ ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());
+
+# undef ENUMERATE_ARRAY_4
+# undef ENUMERATE_ARRAY_16
+# undef ENUMERATE_ARRAY_64
+
+ // Sign the stack so we can identify it for unpoisoning.
+ SignContextStack(ucp);
}
INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
@@ -279,9 +303,6 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
ReadContextStack(ucp, &stack, &ssize);
ClearShadowMemoryForContextStack(stack, ssize);
- // See getcontext interceptor.
- ResetContextStack(oucp);
-
# if __has_attribute(__indirect_return__) && \
(defined(__x86_64__) || defined(__i386__))
int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
@@ -453,7 +474,9 @@ INTERCEPTOR(char*, strdup, const char *s) {
}
GET_STACK_TRACE_MALLOC;
void *new_mem = asan_malloc(length + 1, &stack);
- REAL(memcpy)(new_mem, s, length + 1);
+ if (new_mem) {
+ REAL(memcpy)(new_mem, s, length + 1);
+ }
return reinterpret_cast<char*>(new_mem);
}
@@ -469,7 +492,9 @@ INTERCEPTOR(char*, __strdup, const char *s) {
}
GET_STACK_TRACE_MALLOC;
void *new_mem = asan_malloc(length + 1, &stack);
- REAL(memcpy)(new_mem, s, length + 1);
+ if (new_mem) {
+ REAL(memcpy)(new_mem, s, length + 1);
+ }
return reinterpret_cast<char*>(new_mem);
}
#endif // ASAN_INTERCEPT___STRDUP
@@ -658,11 +683,11 @@ void InitializeAsanInterceptors() {
// Intecept jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
-#if ASAN_INTERCEPT_SWAPCONTEXT
- ASAN_INTERCEPT_FUNC(getcontext);
+# if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
-#endif
-#if ASAN_INTERCEPT__LONGJMP
+ ASAN_INTERCEPT_FUNC(makecontext);
+# endif
+# if ASAN_INTERCEPT__LONGJMP
ASAN_INTERCEPT_FUNC(_longjmp);
#endif
#if ASAN_INTERCEPT___LONGJMP_CHK
@@ -681,11 +706,11 @@ void InitializeAsanInterceptors() {
#endif
// Indirectly intercept std::rethrow_exception.
#if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
- INTERCEPT_FUNCTION(_Unwind_RaiseException);
+ ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);
#endif
// Indirectly intercept std::rethrow_exception.
#if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION
- INTERCEPT_FUNCTION(_Unwind_SjLj_RaiseException);
+ ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);
#endif
// Intercept threading-related functions
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 9a6c22c..c4bf087 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -81,12 +81,7 @@ void InitializePlatformInterceptors();
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \
!SANITIZER_NETBSD
# define ASAN_INTERCEPT___CXA_THROW 1
-# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \
- || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
-# else
-# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0
-# endif
+# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1
# if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__))
# define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1
# else
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index 959fdec..a5348e3 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -105,8 +105,8 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle);
void AsanOnDeadlySignal(int, void *siginfo, void *context);
+void SignContextStack(void *context);
void ReadContextStack(void *context, uptr *stack, uptr *ssize);
-void ResetContextStack(void *context);
void StopInitOrderChecking();
// Wrapper for TLS/TSD.
diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
index 89450fc..e19b447 100644
--- a/libsanitizer/asan/asan_linux.cpp
+++ b/libsanitizer/asan/asan_linux.cpp
@@ -15,55 +15,56 @@
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
-#include "asan_interceptors.h"
-#include "asan_internal.h"
-#include "asan_premap_shadow.h"
-#include "asan_thread.h"
-#include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_freebsd.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_procmaps.h"
-
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/mman.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <unwind.h>
-
-#if SANITIZER_FREEBSD
-#include <sys/link_elf.h>
-#endif
-
-#if SANITIZER_SOLARIS
-#include <link.h>
-#endif
-
-#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
-#include <ucontext.h>
-extern "C" void* _DYNAMIC;
-#elif SANITIZER_NETBSD
-#include <link_elf.h>
-#include <ucontext.h>
+# include <dlfcn.h>
+# include <fcntl.h>
+# include <limits.h>
+# include <pthread.h>
+# include <stdio.h>
+# include <sys/mman.h>
+# include <sys/resource.h>
+# include <sys/syscall.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
+# include <unwind.h>
+
+# include "asan_interceptors.h"
+# include "asan_internal.h"
+# include "asan_premap_shadow.h"
+# include "asan_thread.h"
+# include "sanitizer_common/sanitizer_flags.h"
+# include "sanitizer_common/sanitizer_freebsd.h"
+# include "sanitizer_common/sanitizer_hash.h"
+# include "sanitizer_common/sanitizer_libc.h"
+# include "sanitizer_common/sanitizer_procmaps.h"
+
+# if SANITIZER_FREEBSD
+# include <sys/link_elf.h>
+# endif
+
+# if SANITIZER_SOLARIS
+# include <link.h>
+# endif
+
+# if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
+# include <ucontext.h>
+extern "C" void *_DYNAMIC;
+# elif SANITIZER_NETBSD
+# include <link_elf.h>
+# include <ucontext.h>
extern Elf_Dyn _DYNAMIC;
-#else
-#include <sys/ucontext.h>
-#include <link.h>
+# else
+# include <link.h>
+# include <sys/ucontext.h>
extern ElfW(Dyn) _DYNAMIC[];
-#endif
+# endif
// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
// 32-bit mode.
-#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
- __FreeBSD_version <= 902001 // v9.2
-#define ucontext_t xucontext_t
-#endif
+# if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
+ __FreeBSD_version <= 902001 // v9.2
+# define ucontext_t xucontext_t
+# endif
typedef enum {
ASAN_RT_VERSION_UNDEFINED = 0,
@@ -74,21 +75,21 @@ typedef enum {
// FIXME: perhaps also store abi version here?
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
-asan_rt_version_t __asan_rt_version;
+asan_rt_version_t __asan_rt_version;
}
namespace __asan {
void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {}
-bool IsSystemHeapAddress (uptr addr) { return false; }
+bool IsSystemHeapAddress(uptr addr) { return false; }
void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static.
return &_DYNAMIC;
}
-#if ASAN_PREMAP_SHADOW
+# if ASAN_PREMAP_SHADOW
uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
uptr granularity = GetMmapGranularity();
uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
@@ -98,14 +99,14 @@ uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
return shadow_start;
}
-#endif
+# endif
uptr FindDynamicShadowStart() {
uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);
-#if ASAN_PREMAP_SHADOW
+# if ASAN_PREMAP_SHADOW
if (!PremapShadowFailed())
return FindPremappedShadowStart(shadow_size_bytes);
-#endif
+# endif
return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE,
/*min_shadow_base_alignment*/ 0, kHighMemEnd);
@@ -121,11 +122,11 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
}
-#if SANITIZER_ANDROID
+# if SANITIZER_ANDROID
// FIXME: should we do anything for Android?
void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
-#else
+# else
static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
void *data) {
VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name,
@@ -154,7 +155,7 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
static bool IsDynamicRTName(const char *libname) {
return internal_strstr(libname, "libclang_rt.asan") ||
- internal_strstr(libname, "libasan.so");
+ internal_strstr(libname, "libasan.so");
}
static void ReportIncompatibleRT() {
@@ -170,9 +171,10 @@ void AsanCheckDynamicRTPrereqs() {
const char *first_dso_name = nullptr;
dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) {
- Report("ASan runtime does not come first in initial library list; "
- "you should either link runtime to your application or "
- "manually preload it with LD_PRELOAD.\n");
+ Report(
+ "ASan runtime does not come first in initial library list; "
+ "you should either link runtime to your application or "
+ "manually preload it with LD_PRELOAD.\n");
Die();
}
}
@@ -190,13 +192,14 @@ void AsanCheckIncompatibleRT() {
// as early as possible, otherwise ASan interceptors could bind to
// the functions in dynamic ASan runtime instead of the functions in
// system libraries, causing crashes later in ASan initialization.
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
char filename[PATH_MAX];
MemoryMappedSegment segment(filename, sizeof(filename));
while (proc_maps.Next(&segment)) {
if (IsDynamicRTName(segment.filename)) {
- Report("Your application is linked against "
- "incompatible ASan runtimes.\n");
+ Report(
+ "Your application is linked against "
+ "incompatible ASan runtimes.\n");
Die();
}
}
@@ -206,31 +209,36 @@ void AsanCheckIncompatibleRT() {
}
}
}
-#endif // SANITIZER_ANDROID
+# endif // SANITIZER_ANDROID
-#if !SANITIZER_ANDROID
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
- ucontext_t *ucp = (ucontext_t*)context;
- *stack = (uptr)ucp->uc_stack.ss_sp;
- *ssize = ucp->uc_stack.ss_size;
+# if ASAN_INTERCEPT_SWAPCONTEXT
+constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;
+
+static int HashContextStack(const ucontext_t &ucp) {
+ MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);
+ hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));
+ hash.add(ucp.uc_stack.ss_size);
+ return static_cast<int>(hash.get());
}
-void ResetContextStack(void *context) {
- ucontext_t *ucp = (ucontext_t *)context;
- ucp->uc_stack.ss_sp = nullptr;
- ucp->uc_stack.ss_size = 0;
+void SignContextStack(void *context) {
+ ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
+ ucp->uc_stack.ss_flags = HashContextStack(*ucp);
}
-# else
+
void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
- UNIMPLEMENTED();
+ const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);
+ if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) {
+ *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);
+ *ssize = ucp->uc_stack.ss_size;
+ return;
+ }
+ *stack = 0;
+ *ssize = 0;
}
+# endif // ASAN_INTERCEPT_SWAPCONTEXT
-void ResetContextStack(void *context) { UNIMPLEMENTED(); }
-# endif
-
-void *AsanDlSymNext(const char *sym) {
- return dlsym(RTLD_NEXT, sym);
-}
+void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
bool HandleDlopenInit() {
// Not supported on this platform.
@@ -239,7 +247,7 @@ bool HandleDlopenInit() {
return false;
}
-} // namespace __asan
+} // namespace __asan
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
diff --git a/libsanitizer/asan/asan_mac.cpp b/libsanitizer/asan/asan_mac.cpp
index a2d5c31..c9bd5fb 100644
--- a/libsanitizer/asan/asan_mac.cpp
+++ b/libsanitizer/asan/asan_mac.cpp
@@ -95,12 +95,6 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
}
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
- UNIMPLEMENTED();
-}
-
-void ResetContextStack(void *context) { UNIMPLEMENTED(); }
-
// Support for the following functions from libdispatch on Mac OS:
// dispatch_async_f()
// dispatch_async()
diff --git a/libsanitizer/asan/asan_malloc_win.cpp b/libsanitizer/asan/asan_malloc_win.cpp
index 4b76d4e..ff78d76 100644
--- a/libsanitizer/asan/asan_malloc_win.cpp
+++ b/libsanitizer/asan/asan_malloc_win.cpp
@@ -508,10 +508,10 @@ void ReplaceSystemMalloc() {
TryToOverrideFunction("_expand_base", (uptr)_expand);
if (flags()->windows_hook_rtl_allocators) {
- INTERCEPT_FUNCTION(HeapSize);
- INTERCEPT_FUNCTION(HeapFree);
- INTERCEPT_FUNCTION(HeapReAlloc);
- INTERCEPT_FUNCTION(HeapAlloc);
+ ASAN_INTERCEPT_FUNC(HeapSize);
+ ASAN_INTERCEPT_FUNC(HeapFree);
+ ASAN_INTERCEPT_FUNC(HeapReAlloc);
+ ASAN_INTERCEPT_FUNC(HeapAlloc);
// Undocumented functions must be intercepted by name, not by symbol.
__interception::OverrideFunction("RtlSizeHeap", (uptr)WRAP(RtlSizeHeap),
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index 47ccf84..c5f95c0 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -190,7 +190,7 @@
# elif defined(__aarch64__)
# define ASAN_SHADOW_OFFSET_CONST 0x0000001000000000
# elif defined(__powerpc64__)
-# define ASAN_SHADOW_OFFSET_CONST 0x0000020000000000
+# define ASAN_SHADOW_OFFSET_CONST 0x0000100000000000
# elif defined(__s390x__)
# define ASAN_SHADOW_OFFSET_CONST 0x0010000000000000
# elif SANITIZER_FREEBSD
diff --git a/libsanitizer/asan/asan_memory_profile.cpp b/libsanitizer/asan/asan_memory_profile.cpp
index 4fcd560..3396fc2 100644
--- a/libsanitizer/asan/asan_memory_profile.cpp
+++ b/libsanitizer/asan/asan_memory_profile.cpp
@@ -11,12 +11,11 @@
// This file implements __sanitizer_print_memory_profile.
//===----------------------------------------------------------------------===//
+#include "asan/asan_allocator.h"
+#include "lsan/lsan_common.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
-#include "sanitizer_common/sanitizer_stoptheworld.h"
-#include "lsan/lsan_common.h"
-#include "asan/asan_allocator.h"
#if CAN_SANITIZE_LEAKS
@@ -100,17 +99,16 @@ static void ChunkCallback(uptr chunk, void *arg) {
FindHeapChunkByAllocBeg(chunk));
}
-static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
- void *argument) {
+static void MemoryProfileCB(uptr top_percent, uptr max_number_of_contexts) {
HeapProfile hp;
+ __lsan::LockAllocator();
__lsan::ForEachChunk(ChunkCallback, &hp);
- uptr *Arg = reinterpret_cast<uptr*>(argument);
- hp.Print(Arg[0], Arg[1]);
+ __lsan::UnlockAllocator();
+ hp.Print(top_percent, max_number_of_contexts);
if (Verbosity())
__asan_print_accumulated_stats();
}
-
} // namespace __asan
#endif // CAN_SANITIZE_LEAKS
@@ -120,10 +118,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_print_memory_profile(uptr top_percent,
uptr max_number_of_contexts) {
#if CAN_SANITIZE_LEAKS
- uptr Arg[2];
- Arg[0] = top_percent;
- Arg[1] = max_number_of_contexts;
- __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg);
+ __asan::MemoryProfileCB(top_percent, max_number_of_contexts);
#endif // CAN_SANITIZE_LEAKS
}
} // extern "C"
diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
index e470256..5164b7d 100644
--- a/libsanitizer/asan/asan_poisoning.cpp
+++ b/libsanitizer/asan/asan_poisoning.cpp
@@ -370,79 +370,77 @@ void __asan_unpoison_stack_memory(uptr addr, uptr size) {
PoisonAlignedStackMemory(addr, size, false);
}
+static void FixUnalignedStorage(uptr storage_beg, uptr storage_end,
+ uptr &old_beg, uptr &old_end, uptr &new_beg,
+ uptr &new_end) {
+ constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+ if (UNLIKELY(!AddrIsAlignedByGranularity(storage_end))) {
+ uptr end_down = RoundDownTo(storage_end, granularity);
+ // Ignore the last unaligned granule if the storage is followed by
+ // unpoisoned byte, because we can't poison the prefix anyway. Don't call
+ // AddressIsPoisoned at all if container changes does not affect the last
+ // granule at all.
+ if ((((old_end != new_end) && Max(old_end, new_end) > end_down) ||
+ ((old_beg != new_beg) && Max(old_beg, new_beg) > end_down)) &&
+ !AddressIsPoisoned(storage_end)) {
+ old_beg = Min(end_down, old_beg);
+ old_end = Min(end_down, old_end);
+ new_beg = Min(end_down, new_beg);
+ new_end = Min(end_down, new_end);
+ }
+ }
+
+ // Handle misaligned begin and cut it off.
+ if (UNLIKELY(!AddrIsAlignedByGranularity(storage_beg))) {
+ uptr beg_up = RoundUpTo(storage_beg, granularity);
+ // The first unaligned granule needs special handling only if we had bytes
+ // there before and will have none after.
+ if ((new_beg == new_end || new_beg >= beg_up) && old_beg != old_end &&
+ old_beg < beg_up) {
+ // Keep granule prefix outside of the storage unpoisoned.
+ uptr beg_down = RoundDownTo(storage_beg, granularity);
+ *(u8 *)MemToShadow(beg_down) = storage_beg - beg_down;
+ old_beg = Max(beg_up, old_beg);
+ old_end = Max(beg_up, old_end);
+ new_beg = Max(beg_up, new_beg);
+ new_end = Max(beg_up, new_end);
+ }
+ }
+}
+
void __sanitizer_annotate_contiguous_container(const void *beg_p,
const void *end_p,
const void *old_mid_p,
const void *new_mid_p) {
- if (!flags()->detect_container_overflow) return;
+ if (!flags()->detect_container_overflow)
+ return;
VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
new_mid_p);
- uptr beg = reinterpret_cast<uptr>(beg_p);
- uptr end = reinterpret_cast<uptr>(end_p);
- uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
- uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
+ uptr storage_beg = reinterpret_cast<uptr>(beg_p);
+ uptr storage_end = reinterpret_cast<uptr>(end_p);
+ uptr old_end = reinterpret_cast<uptr>(old_mid_p);
+ uptr new_end = reinterpret_cast<uptr>(new_mid_p);
+ uptr old_beg = storage_beg;
+ uptr new_beg = storage_beg;
uptr granularity = ASAN_SHADOW_GRANULARITY;
- if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end)) {
+ if (!(storage_beg <= old_end && storage_beg <= new_end &&
+ old_end <= storage_end && new_end <= storage_end)) {
GET_STACK_TRACE_FATAL_HERE;
- ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
- &stack);
+ ReportBadParamsToAnnotateContiguousContainer(storage_beg, storage_end,
+ old_end, new_end, &stack);
}
- CHECK_LE(end - beg,
- FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
+ CHECK_LE(storage_end - storage_beg,
+ FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
- if (old_mid == new_mid)
+ if (old_end == new_end)
return; // Nothing to do here.
- // Handle misaligned end and cut it off.
- if (UNLIKELY(!AddrIsAlignedByGranularity(end))) {
- uptr end_down = RoundDownTo(end, granularity);
- // Either new or old mid must be in the granule to affect it.
- if (new_mid > end_down) {
- if (AddressIsPoisoned(end)) {
- *(u8 *)MemToShadow(end_down) = static_cast<u8>(new_mid - end_down);
- } else {
- // Something after the container - don't touch.
- }
- } else if (old_mid > end_down) {
- if (AddressIsPoisoned(end)) {
- *(u8 *)MemToShadow(end_down) = kAsanContiguousContainerOOBMagic;
- } else {
- // Something after the container - don't touch.
- }
- }
+ FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg,
+ new_end);
- if (beg >= end_down)
- return; // Same granule.
-
- old_mid = Min(end_down, old_mid);
- new_mid = Min(end_down, new_mid);
- }
-
- // Handle misaligned begin and cut it off.
- if (UNLIKELY(!AddrIsAlignedByGranularity(beg))) {
- uptr beg_up = RoundUpTo(beg, granularity);
- uptr beg_down = RoundDownTo(beg, granularity);
- // As soon as we add first byte into container we will not be able to
- // determine the state of the byte before the container. So we assume it's
- // always unpoison.
-
- // Either new or old mid must be in the granule to affect it.
- if (new_mid < beg_up) {
- *(u8 *)MemToShadow(beg_down) = static_cast<u8>(new_mid - beg_down);
- } else if (old_mid < beg_up) {
- *(u8 *)MemToShadow(beg_down) = 0;
- }
-
- old_mid = Max(beg_up, old_mid);
- new_mid = Max(beg_up, new_mid);
- }
-
- if (old_mid == new_mid)
- return;
-
- uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
- uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
- uptr d1 = RoundDownTo(old_mid, granularity);
+ uptr a = RoundDownTo(Min(old_end, new_end), granularity);
+ uptr c = RoundUpTo(Max(old_end, new_end), granularity);
+ uptr d1 = RoundDownTo(old_end, granularity);
// uptr d2 = RoundUpTo(old_mid, granularity);
// Currently we should be in this state:
// [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
@@ -453,23 +451,148 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
// if (d1 != d2)
// CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
if (a + granularity <= d1)
- CHECK_EQ(*(u8*)MemToShadow(a), 0);
+ CHECK_EQ(*(u8 *)MemToShadow(a), 0);
// if (d2 + granularity <= c && c <= end)
// CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
// kAsanContiguousContainerOOBMagic);
- uptr b1 = RoundDownTo(new_mid, granularity);
- uptr b2 = RoundUpTo(new_mid, granularity);
+ uptr b1 = RoundDownTo(new_end, granularity);
+ uptr b2 = RoundUpTo(new_end, granularity);
// New state:
// [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
- PoisonShadow(a, b1 - a, 0);
- PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
+ if (b1 > a)
+ PoisonShadow(a, b1 - a, 0);
+ else if (c > b2)
+ PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
if (b1 != b2) {
CHECK_EQ(b2 - b1, granularity);
- *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
+ *(u8 *)MemToShadow(b1) = static_cast<u8>(new_end - b1);
}
}
+// Annotates a double ended contiguous memory area like std::deque's chunk.
+// It allows detecting buggy accesses to allocated but not used begining
+// or end items of such a container.
+void __sanitizer_annotate_double_ended_contiguous_container(
+ const void *storage_beg_p, const void *storage_end_p,
+ const void *old_container_beg_p, const void *old_container_end_p,
+ const void *new_container_beg_p, const void *new_container_end_p) {
+ if (!flags()->detect_container_overflow)
+ return;
+
+ VPrintf(2, "contiguous_container: %p %p %p %p %p %p\n", storage_beg_p,
+ storage_end_p, old_container_beg_p, old_container_end_p,
+ new_container_beg_p, new_container_end_p);
+
+ uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p);
+ uptr storage_end = reinterpret_cast<uptr>(storage_end_p);
+ uptr old_beg = reinterpret_cast<uptr>(old_container_beg_p);
+ uptr old_end = reinterpret_cast<uptr>(old_container_end_p);
+ uptr new_beg = reinterpret_cast<uptr>(new_container_beg_p);
+ uptr new_end = reinterpret_cast<uptr>(new_container_end_p);
+
+ constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+
+ if (!(old_beg <= old_end && new_beg <= new_end) ||
+ !(storage_beg <= new_beg && new_end <= storage_end) ||
+ !(storage_beg <= old_beg && old_end <= storage_end)) {
+ GET_STACK_TRACE_FATAL_HERE;
+ ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
+ storage_beg, storage_end, old_beg, old_end, new_beg, new_end, &stack);
+ }
+ CHECK_LE(storage_end - storage_beg,
+ FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
+
+ if ((old_beg == old_end && new_beg == new_end) ||
+ (old_beg == new_beg && old_end == new_end))
+ return; // Nothing to do here.
+
+ FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg,
+ new_end);
+
+ // Handle non-intersecting new/old containers separately have simpler
+ // intersecting case.
+ if (old_beg == old_end || new_beg == new_end || new_end <= old_beg ||
+ old_end <= new_beg) {
+ if (old_beg != old_end) {
+ // Poisoning the old container.
+ uptr a = RoundDownTo(old_beg, granularity);
+ uptr b = RoundUpTo(old_end, granularity);
+ PoisonShadow(a, b - a, kAsanContiguousContainerOOBMagic);
+ }
+
+ if (new_beg != new_end) {
+ // Unpoisoning the new container.
+ uptr a = RoundDownTo(new_beg, granularity);
+ uptr b = RoundDownTo(new_end, granularity);
+ PoisonShadow(a, b - a, 0);
+ if (!AddrIsAlignedByGranularity(new_end))
+ *(u8 *)MemToShadow(b) = static_cast<u8>(new_end - b);
+ }
+
+ return;
+ }
+
+ // Intersection of old and new containers is not empty.
+ CHECK_LT(new_beg, old_end);
+ CHECK_GT(new_end, old_beg);
+
+ if (new_beg < old_beg) {
+ // Round down because we can't poison prefixes.
+ uptr a = RoundDownTo(new_beg, granularity);
+ // Round down and ignore the [c, old_beg) as its state defined by unchanged
+ // [old_beg, old_end).
+ uptr c = RoundDownTo(old_beg, granularity);
+ PoisonShadow(a, c - a, 0);
+ } else if (new_beg > old_beg) {
+ // Round down and poison [a, old_beg) because it was unpoisoned only as a
+ // prefix.
+ uptr a = RoundDownTo(old_beg, granularity);
+ // Round down and ignore the [c, new_beg) as its state defined by unchanged
+ // [new_beg, old_end).
+ uptr c = RoundDownTo(new_beg, granularity);
+
+ PoisonShadow(a, c - a, kAsanContiguousContainerOOBMagic);
+ }
+
+ if (new_end > old_end) {
+ // Round down to poison the prefix.
+ uptr a = RoundDownTo(old_end, granularity);
+ // Round down and handle remainder below.
+ uptr c = RoundDownTo(new_end, granularity);
+ PoisonShadow(a, c - a, 0);
+ if (!AddrIsAlignedByGranularity(new_end))
+ *(u8 *)MemToShadow(c) = static_cast<u8>(new_end - c);
+ } else if (new_end < old_end) {
+ // Round up and handle remained below.
+ uptr a2 = RoundUpTo(new_end, granularity);
+ // Round up to poison entire granule as we had nothing in [old_end, c2).
+ uptr c2 = RoundUpTo(old_end, granularity);
+ PoisonShadow(a2, c2 - a2, kAsanContiguousContainerOOBMagic);
+
+ if (!AddrIsAlignedByGranularity(new_end)) {
+ uptr a = RoundDownTo(new_end, granularity);
+ *(u8 *)MemToShadow(a) = static_cast<u8>(new_end - a);
+ }
+ }
+}
+
+static const void *FindBadAddress(uptr begin, uptr end, bool poisoned) {
+ CHECK_LE(begin, end);
+ constexpr uptr kMaxRangeToCheck = 32;
+ if (end - begin > kMaxRangeToCheck * 2) {
+ if (auto *bad = FindBadAddress(begin, begin + kMaxRangeToCheck, poisoned))
+ return bad;
+ if (auto *bad = FindBadAddress(end - kMaxRangeToCheck, end, poisoned))
+ return bad;
+ }
+
+ for (uptr i = begin; i < end; ++i)
+ if (AddressIsPoisoned(i) != poisoned)
+ return reinterpret_cast<const void *>(i);
+ return nullptr;
+}
+
const void *__sanitizer_contiguous_container_find_bad_address(
const void *beg_p, const void *mid_p, const void *end_p) {
if (!flags()->detect_container_overflow)
@@ -477,35 +600,22 @@ const void *__sanitizer_contiguous_container_find_bad_address(
uptr granularity = ASAN_SHADOW_GRANULARITY;
uptr beg = reinterpret_cast<uptr>(beg_p);
uptr end = reinterpret_cast<uptr>(end_p);
+ uptr mid = reinterpret_cast<uptr>(mid_p);
+ CHECK_LE(beg, mid);
+ CHECK_LE(mid, end);
+ // If the byte after the storage is unpoisoned, everything in the granule
+ // before must stay unpoisoned.
uptr annotations_end =
(!AddrIsAlignedByGranularity(end) && !AddressIsPoisoned(end))
? RoundDownTo(end, granularity)
: end;
- uptr mid = reinterpret_cast<uptr>(mid_p);
- CHECK_LE(beg, mid);
- CHECK_LE(mid, end);
- // Check some bytes starting from beg, some bytes around mid, and some bytes
- // ending with end.
- uptr kMaxRangeToCheck = 32;
- uptr r1_beg = beg;
- uptr r1_end = Min(beg + kMaxRangeToCheck, mid);
- uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
- uptr r2_end = Min(annotations_end, mid + kMaxRangeToCheck);
- uptr r3_beg = Max(annotations_end - kMaxRangeToCheck, mid);
- uptr r3_end = annotations_end;
- for (uptr i = r1_beg; i < r1_end; i++)
- if (AddressIsPoisoned(i))
- return reinterpret_cast<const void *>(i);
- for (uptr i = r2_beg; i < mid; i++)
- if (AddressIsPoisoned(i))
- return reinterpret_cast<const void *>(i);
- for (uptr i = mid; i < r2_end; i++)
- if (!AddressIsPoisoned(i))
- return reinterpret_cast<const void *>(i);
- for (uptr i = r3_beg; i < r3_end; i++)
- if (!AddressIsPoisoned(i))
- return reinterpret_cast<const void *>(i);
- return nullptr;
+ beg = Min(beg, annotations_end);
+ mid = Min(mid, annotations_end);
+ if (auto *bad = FindBadAddress(beg, mid, false))
+ return bad;
+ if (auto *bad = FindBadAddress(mid, annotations_end, true))
+ return bad;
+ return FindBadAddress(annotations_end, end, false);
}
int __sanitizer_verify_contiguous_container(const void *beg_p,
@@ -515,6 +625,48 @@ int __sanitizer_verify_contiguous_container(const void *beg_p,
end_p) == nullptr;
}
+const void *__sanitizer_double_ended_contiguous_container_find_bad_address(
+ const void *storage_beg_p, const void *container_beg_p,
+ const void *container_end_p, const void *storage_end_p) {
+ if (!flags()->detect_container_overflow)
+ return nullptr;
+ uptr granularity = ASAN_SHADOW_GRANULARITY;
+ uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p);
+ uptr storage_end = reinterpret_cast<uptr>(storage_end_p);
+ uptr beg = reinterpret_cast<uptr>(container_beg_p);
+ uptr end = reinterpret_cast<uptr>(container_end_p);
+
+ // The prefix of the firs granule of the container is unpoisoned.
+ if (beg != end)
+ beg = Max(storage_beg, RoundDownTo(beg, granularity));
+
+ // If the byte after the storage is unpoisoned, the prefix of the last granule
+ // is unpoisoned.
+ uptr annotations_end = (!AddrIsAlignedByGranularity(storage_end) &&
+ !AddressIsPoisoned(storage_end))
+ ? RoundDownTo(storage_end, granularity)
+ : storage_end;
+ storage_beg = Min(storage_beg, annotations_end);
+ beg = Min(beg, annotations_end);
+ end = Min(end, annotations_end);
+
+ if (auto *bad = FindBadAddress(storage_beg, beg, true))
+ return bad;
+ if (auto *bad = FindBadAddress(beg, end, false))
+ return bad;
+ if (auto *bad = FindBadAddress(end, annotations_end, true))
+ return bad;
+ return FindBadAddress(annotations_end, storage_end, false);
+}
+
+int __sanitizer_verify_double_ended_contiguous_container(
+ const void *storage_beg_p, const void *container_beg_p,
+ const void *container_end_p, const void *storage_end_p) {
+ return __sanitizer_double_ended_contiguous_container_find_bad_address(
+ storage_beg_p, container_beg_p, container_end_p, storage_end_p) ==
+ nullptr;
+}
+
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp
index 2a55d6c..f2c0434 100644
--- a/libsanitizer/asan/asan_report.cpp
+++ b/libsanitizer/asan/asan_report.cpp
@@ -354,6 +354,18 @@ void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
in_report.ReportError(error);
}
+void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
+ uptr storage_beg, uptr storage_end, uptr old_container_beg,
+ uptr old_container_end, uptr new_container_beg, uptr new_container_end,
+ BufferedStackTrace *stack) {
+ ScopedInErrorReport in_report;
+ ErrorBadParamsToAnnotateDoubleEndedContiguousContainer error(
+ GetCurrentTidOrInvalid(), stack, storage_beg, storage_end,
+ old_container_beg, old_container_end, new_container_beg,
+ new_container_end);
+ in_report.ReportError(error);
+}
+
void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2) {
ScopedInErrorReport in_report;
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index dcf6089..248e30d 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -83,6 +83,10 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
uptr old_mid, uptr new_mid,
BufferedStackTrace *stack);
+void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
+ uptr storage_beg, uptr storage_end, uptr old_container_beg,
+ uptr old_container_end, uptr new_container_beg, uptr new_container_end,
+ BufferedStackTrace *stack);
void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
const __asan_global *g2, u32 stack_id2);
diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
index c15963e1..3f6e58e 100644
--- a/libsanitizer/asan/asan_thread.cpp
+++ b/libsanitizer/asan/asan_thread.cpp
@@ -10,17 +10,18 @@
//
// Thread-related code.
//===----------------------------------------------------------------------===//
+#include "asan_thread.h"
+
#include "asan_allocator.h"
#include "asan_interceptors.h"
+#include "asan_mapping.h"
#include "asan_poisoning.h"
#include "asan_stack.h"
-#include "asan_thread.h"
-#include "asan_mapping.h"
+#include "lsan/lsan_common.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
-#include "lsan/lsan_common.h"
namespace __asan {
@@ -306,6 +307,7 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
&tls_begin_, &tls_size);
stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY);
+ stack_bottom_ = RoundDownTo(stack_bottom_, ASAN_SHADOW_GRANULARITY);
tls_end_ = tls_begin_ + tls_size;
dtls_ = DTLS_Get();
@@ -478,6 +480,17 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
+void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); }
+
+void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); }
+
+static ThreadRegistry *GetAsanThreadRegistryLocked() {
+ __asan::asanThreadRegistry().CheckLocked();
+ return &__asan::asanThreadRegistry();
+}
+
+void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); }
+
bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
uptr *cache_end, DTLS **dtls) {
@@ -496,33 +509,76 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
-void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
- void *arg) {
+void GetThreadExtraStackRangesLocked(tid_t os_id,
+ InternalMmapVector<Range> *ranges) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
if (!t)
return;
__asan::FakeStack *fake_stack = t->get_fake_stack();
if (!fake_stack)
return;
- fake_stack->ForEachFakeFrame(callback, arg);
+
+ fake_stack->ForEachFakeFrame(
+ [](uptr begin, uptr end, void *arg) {
+ reinterpret_cast<InternalMmapVector<Range> *>(arg)->push_back(
+ {begin, end});
+ },
+ ranges);
}
-void LockThreadRegistry() {
- __asan::asanThreadRegistry().Lock();
+void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) {
+ GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+ [](ThreadContextBase *tctx, void *arg) {
+ GetThreadExtraStackRangesLocked(
+ tctx->os_id, reinterpret_cast<InternalMmapVector<Range> *>(arg));
+ },
+ ranges);
}
-void UnlockThreadRegistry() {
- __asan::asanThreadRegistry().Unlock();
+void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
+ GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+ [](ThreadContextBase *tctx, void *ptrs) {
+ // Look for the arg pointer of threads that have been created or are
+ // running. This is necessary to prevent false positive leaks due to the
+ // AsanThread holding the only live reference to a heap object. This
+ // can happen because the `pthread_create()` interceptor doesn't wait
+ // for the child thread to start before returning and thus loosing the
+ // the only live reference to the heap object on the stack.
+
+ __asan::AsanThreadContext *atctx =
+ static_cast<__asan::AsanThreadContext *>(tctx);
+
+ // Note ThreadStatusRunning is required because there is a small window
+ // where the thread status switches to `ThreadStatusRunning` but the
+ // `arg` pointer still isn't on the stack yet.
+ if (atctx->status != ThreadStatusCreated &&
+ atctx->status != ThreadStatusRunning)
+ return;
+
+ uptr thread_arg = reinterpret_cast<uptr>(atctx->thread->get_arg());
+ if (!thread_arg)
+ return;
+
+ auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
+ ptrsVec->push_back(thread_arg);
+ },
+ ptrs);
}
-ThreadRegistry *GetThreadRegistryLocked() {
- __asan::asanThreadRegistry().CheckLocked();
- return &__asan::asanThreadRegistry();
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
+ GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+ [](ThreadContextBase *tctx, void *threads) {
+ if (tctx->status == ThreadStatusRunning)
+ reinterpret_cast<InternalMmapVector<tid_t> *>(threads)->push_back(
+ tctx->os_id);
+ },
+ threads);
}
-void EnsureMainThreadIDIsCorrect() {
- __asan::EnsureMainThreadIDIsCorrect();
+void FinishThreadLocked(u32 tid) {
+ GetAsanThreadRegistryLocked()->FinishThread(tid);
}
+
} // namespace __lsan
// ---------------------- Interface ---------------- {{{1
diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
index f11df06..7dbd7ab 100644
--- a/libsanitizer/asan/asan_win.cpp
+++ b/libsanitizer/asan/asan_win.cpp
@@ -263,12 +263,6 @@ void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
- UNIMPLEMENTED();
-}
-
-void ResetContextStack(void *context) { UNIMPLEMENTED(); }
-
void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); }
bool PlatformUnpoisonStacks() { return false; }