2012-06-04 21:55:19 +08:00
|
|
|
//===-- tsan_mman.cc ------------------------------------------------------===//
|
2012-05-10 21:48:04 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file is a part of ThreadSanitizer (TSan), a race detector.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2017-07-19 03:11:04 +08:00
|
|
|
#include "sanitizer_common/sanitizer_allocator_checks.h"
|
2014-07-08 01:39:31 +08:00
|
|
|
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
#include "sanitizer_common/sanitizer_allocator_report.h"
|
2012-06-07 19:54:08 +08:00
|
|
|
#include "sanitizer_common/sanitizer_common.h"
|
2017-10-12 05:20:04 +08:00
|
|
|
#include "sanitizer_common/sanitizer_errno.h"
|
2012-08-15 23:35:15 +08:00
|
|
|
#include "sanitizer_common/sanitizer_placement_new.h"
|
2012-05-10 21:48:04 +08:00
|
|
|
#include "tsan_mman.h"
|
|
|
|
#include "tsan_rtl.h"
|
|
|
|
#include "tsan_report.h"
|
|
|
|
#include "tsan_flags.h"
|
|
|
|
|
2012-09-24 21:19:47 +08:00
|
|
|
// May be overriden by front-end.
|
2015-11-30 21:27:18 +08:00
|
|
|
SANITIZER_WEAK_DEFAULT_IMPL
|
|
|
|
void __sanitizer_malloc_hook(void *ptr, uptr size) {
|
2014-07-08 01:39:31 +08:00
|
|
|
(void)ptr;
|
|
|
|
(void)size;
|
|
|
|
}
|
2012-09-24 21:19:47 +08:00
|
|
|
|
2015-11-30 21:27:18 +08:00
|
|
|
SANITIZER_WEAK_DEFAULT_IMPL
|
|
|
|
void __sanitizer_free_hook(void *ptr) {
|
2014-07-08 01:39:31 +08:00
|
|
|
(void)ptr;
|
|
|
|
}
|
2012-09-24 21:19:47 +08:00
|
|
|
|
2012-05-10 21:48:04 +08:00
|
|
|
namespace __tsan {
|
|
|
|
|
2013-03-18 18:32:21 +08:00
|
|
|
struct MapUnmapCallback {
|
|
|
|
void OnMap(uptr p, uptr size) const { }
|
|
|
|
void OnUnmap(uptr p, uptr size) const {
|
|
|
|
// We are about to unmap a chunk of user memory.
|
|
|
|
// Mark the corresponding shadow memory as not needed.
|
2013-03-18 23:49:07 +08:00
|
|
|
DontNeedShadowFor(p, size);
|
2015-06-24 19:51:41 +08:00
|
|
|
// Mark the corresponding meta shadow memory as not needed.
|
|
|
|
// Note the block does not contain any meta info at this point
|
|
|
|
// (this happens after free).
|
|
|
|
const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
|
|
|
|
const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
|
|
|
|
// Block came from LargeMmapAllocator, so must be large.
|
|
|
|
// We rely on this in the calculations below.
|
|
|
|
CHECK_GE(size, 2 * kPageSize);
|
|
|
|
uptr diff = RoundUp(p, kPageSize) - p;
|
|
|
|
if (diff != 0) {
|
|
|
|
p += diff;
|
|
|
|
size -= diff;
|
|
|
|
}
|
|
|
|
diff = p + size - RoundDown(p + size, kPageSize);
|
|
|
|
if (diff != 0)
|
|
|
|
size -= diff;
|
2016-12-01 04:41:59 +08:00
|
|
|
uptr p_meta = (uptr)MemToMeta(p);
|
|
|
|
ReleaseMemoryPagesToOS(p_meta, p_meta + size / kMetaRatio);
|
2013-03-18 18:32:21 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-08-30 21:02:30 +08:00
|
|
|
static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64);
|
|
|
|
Allocator *allocator() {
|
2012-08-15 23:35:15 +08:00
|
|
|
return reinterpret_cast<Allocator*>(&allocator_placeholder);
|
|
|
|
}
|
|
|
|
|
2016-05-07 03:35:22 +08:00
|
|
|
struct GlobalProc {
|
|
|
|
Mutex mtx;
|
|
|
|
Processor *proc;
|
|
|
|
|
|
|
|
GlobalProc()
|
|
|
|
: mtx(MutexTypeGlobalProc, StatMtxGlobalProc)
|
|
|
|
, proc(ProcCreate()) {
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64);
|
|
|
|
GlobalProc *global_proc() {
|
|
|
|
return reinterpret_cast<GlobalProc*>(&global_proc_placeholder);
|
|
|
|
}
|
|
|
|
|
2016-05-10 19:19:50 +08:00
|
|
|
ScopedGlobalProcessor::ScopedGlobalProcessor() {
|
|
|
|
GlobalProc *gp = global_proc();
|
|
|
|
ThreadState *thr = cur_thread();
|
|
|
|
if (thr->proc())
|
|
|
|
return;
|
|
|
|
// If we don't have a proc, use the global one.
|
|
|
|
// There are currently only two known case where this path is triggered:
|
|
|
|
// __interceptor_free
|
|
|
|
// __nptl_deallocate_tsd
|
|
|
|
// start_thread
|
|
|
|
// clone
|
|
|
|
// and:
|
|
|
|
// ResetRange
|
|
|
|
// __interceptor_munmap
|
|
|
|
// __deallocate_stack
|
|
|
|
// start_thread
|
|
|
|
// clone
|
|
|
|
// Ideally, we destroy thread state (and unwire proc) when a thread actually
|
|
|
|
// exits (i.e. when we join/wait it). Then we would not need the global proc
|
|
|
|
gp->mtx.Lock();
|
|
|
|
ProcWire(gp->proc, thr);
|
|
|
|
}
|
|
|
|
|
|
|
|
ScopedGlobalProcessor::~ScopedGlobalProcessor() {
|
|
|
|
GlobalProc *gp = global_proc();
|
|
|
|
ThreadState *thr = cur_thread();
|
|
|
|
if (thr->proc() != gp->proc)
|
|
|
|
return;
|
|
|
|
ProcUnwire(gp->proc, thr);
|
|
|
|
gp->mtx.Unlock();
|
|
|
|
}
|
|
|
|
|
2012-08-15 23:35:15 +08:00
|
|
|
void InitializeAllocator() {
|
2017-06-21 05:23:02 +08:00
|
|
|
SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
|
|
|
|
allocator()->Init(common_flags()->allocator_release_to_os_interval_ms);
|
2012-08-15 23:35:15 +08:00
|
|
|
}
|
|
|
|
|
2016-05-07 03:35:22 +08:00
|
|
|
void InitializeAllocatorLate() {
|
|
|
|
new(global_proc()) GlobalProc();
|
|
|
|
}
|
|
|
|
|
2016-04-27 16:23:02 +08:00
|
|
|
void AllocatorProcStart(Processor *proc) {
|
|
|
|
allocator()->InitCache(&proc->alloc_cache);
|
|
|
|
internal_allocator()->InitCache(&proc->internal_alloc_cache);
|
2013-01-24 17:08:03 +08:00
|
|
|
}
|
|
|
|
|
2016-04-27 16:23:02 +08:00
|
|
|
void AllocatorProcFinish(Processor *proc) {
|
|
|
|
allocator()->DestroyCache(&proc->alloc_cache);
|
|
|
|
internal_allocator()->DestroyCache(&proc->internal_alloc_cache);
|
2013-01-24 17:08:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AllocatorPrintStats() {
|
|
|
|
allocator()->PrintStats();
|
2012-08-15 23:35:15 +08:00
|
|
|
}
|
|
|
|
|
2012-05-10 21:48:04 +08:00
|
|
|
static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
|
2015-09-03 19:20:46 +08:00
|
|
|
if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
|
2014-09-02 20:27:45 +08:00
|
|
|
!flags()->report_signal_unsafe)
|
2012-05-10 21:48:04 +08:00
|
|
|
return;
|
2014-11-04 06:23:44 +08:00
|
|
|
VarSizeStackTrace stack;
|
|
|
|
ObtainCurrentStack(thr, pc, &stack);
|
2015-09-03 19:20:46 +08:00
|
|
|
if (IsFiredSuppression(ctx, ReportTypeSignalUnsafe, stack))
|
|
|
|
return;
|
2013-03-15 21:48:44 +08:00
|
|
|
ThreadRegistryLock l(ctx->thread_registry);
|
2012-05-10 21:48:04 +08:00
|
|
|
ScopedReport rep(ReportTypeSignalUnsafe);
|
2015-09-03 19:20:46 +08:00
|
|
|
rep.AddStack(stack, true);
|
|
|
|
OutputReport(thr, rep);
|
2012-05-10 21:48:04 +08:00
|
|
|
}
|
|
|
|
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
static constexpr uptr kMaxAllowedMallocSize = 1ull << 40;
|
|
|
|
|
2017-07-25 05:22:59 +08:00
|
|
|
void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align,
|
|
|
|
bool signal) {
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize) {
|
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return nullptr;
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportAllocationSizeTooBig(sz, kMaxAllowedMallocSize, &stack);
|
|
|
|
}
|
2016-04-27 20:30:48 +08:00
|
|
|
void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align);
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (UNLIKELY(!p)) {
|
|
|
|
SetAllocatorOutOfMemory();
|
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return nullptr;
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportOutOfMemory(sz, &stack);
|
|
|
|
}
|
2014-05-29 21:50:54 +08:00
|
|
|
if (ctx && ctx->initialized)
|
|
|
|
OnUserAlloc(thr, pc, (uptr)p, sz, true);
|
2014-10-15 16:56:43 +08:00
|
|
|
if (signal)
|
|
|
|
SignalUnsafeCall(thr, pc);
|
2012-05-10 21:48:04 +08:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2014-10-15 16:56:43 +08:00
|
|
|
void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
|
2016-05-10 19:19:50 +08:00
|
|
|
ScopedGlobalProcessor sgp;
|
2014-05-29 21:50:54 +08:00
|
|
|
if (ctx && ctx->initialized)
|
|
|
|
OnUserFree(thr, pc, (uptr)p, true);
|
2016-04-27 20:30:48 +08:00
|
|
|
allocator()->Deallocate(&thr->proc()->alloc_cache, p);
|
2014-10-15 16:56:43 +08:00
|
|
|
if (signal)
|
|
|
|
SignalUnsafeCall(thr, pc);
|
2012-05-10 21:48:04 +08:00
|
|
|
}
|
|
|
|
|
2017-07-25 05:22:59 +08:00
|
|
|
void *user_alloc(ThreadState *thr, uptr pc, uptr sz) {
|
|
|
|
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, kDefaultAlignment));
|
|
|
|
}
|
|
|
|
|
|
|
|
void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (UNLIKELY(CheckForCallocOverflow(size, n))) {
|
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return SetErrnoOnNull(nullptr);
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportCallocOverflow(n, size, &stack);
|
|
|
|
}
|
2017-07-25 05:22:59 +08:00
|
|
|
void *p = user_alloc_internal(thr, pc, n * size);
|
|
|
|
if (p)
|
|
|
|
internal_memset(p, 0, n * size);
|
|
|
|
return SetErrnoOnNull(p);
|
|
|
|
}
|
|
|
|
|
2014-05-29 21:50:54 +08:00
|
|
|
void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
|
|
|
|
DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
|
|
|
|
ctx->metamap.AllocBlock(thr, pc, p, sz);
|
|
|
|
if (write && thr->ignore_reads_and_writes == 0)
|
|
|
|
MemoryRangeImitateWrite(thr, pc, (uptr)p, sz);
|
|
|
|
else
|
|
|
|
MemoryResetRange(thr, pc, (uptr)p, sz);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) {
|
|
|
|
CHECK_NE(p, (void*)0);
|
2016-04-27 20:30:48 +08:00
|
|
|
uptr sz = ctx->metamap.FreeBlock(thr->proc(), p);
|
2014-05-29 21:50:54 +08:00
|
|
|
DPrintf("#%d: free(%p, %zu)\n", thr->tid, p, sz);
|
|
|
|
if (write && thr->ignore_reads_and_writes == 0)
|
|
|
|
MemoryRangeFreed(thr, pc, (uptr)p, sz);
|
|
|
|
}
|
|
|
|
|
2012-05-10 21:48:04 +08:00
|
|
|
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
|
|
|
|
// FIXME: Handle "shrinking" more efficiently,
|
|
|
|
// it seems that some software actually does this.
|
2017-07-25 05:22:59 +08:00
|
|
|
if (!p)
|
|
|
|
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz));
|
|
|
|
if (!sz) {
|
2012-05-10 21:48:04 +08:00
|
|
|
user_free(thr, pc, p);
|
2017-07-25 05:22:59 +08:00
|
|
|
return nullptr;
|
2016-08-02 22:22:12 +08:00
|
|
|
}
|
2017-07-25 05:22:59 +08:00
|
|
|
void *new_p = user_alloc_internal(thr, pc, sz);
|
|
|
|
if (new_p) {
|
|
|
|
uptr old_sz = user_alloc_usable_size(p);
|
|
|
|
internal_memcpy(new_p, p, min(old_sz, sz));
|
|
|
|
user_free(thr, pc, p);
|
|
|
|
}
|
|
|
|
return SetErrnoOnNull(new_p);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) {
|
|
|
|
if (UNLIKELY(!IsPowerOfTwo(align))) {
|
|
|
|
errno = errno_EINVAL;
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return nullptr;
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportInvalidAllocationAlignment(align, &stack);
|
2017-07-25 05:22:59 +08:00
|
|
|
}
|
|
|
|
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align));
|
|
|
|
}
|
|
|
|
|
|
|
|
int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align,
|
|
|
|
uptr sz) {
|
|
|
|
if (UNLIKELY(!CheckPosixMemalignAlignment(align))) {
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return errno_EINVAL;
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportInvalidPosixMemalignAlignment(align, &stack);
|
2017-07-25 05:22:59 +08:00
|
|
|
}
|
|
|
|
void *ptr = user_alloc_internal(thr, pc, sz, align);
|
|
|
|
if (UNLIKELY(!ptr))
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
// OOM error is already taken care of by user_alloc_internal.
|
2017-07-25 05:22:59 +08:00
|
|
|
return errno_ENOMEM;
|
|
|
|
CHECK(IsAligned((uptr)ptr, align));
|
|
|
|
*memptr = ptr;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) {
|
|
|
|
if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) {
|
|
|
|
errno = errno_EINVAL;
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return nullptr;
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportInvalidAlignedAllocAlignment(sz, align, &stack);
|
2017-07-25 05:22:59 +08:00
|
|
|
}
|
|
|
|
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align));
|
|
|
|
}
|
|
|
|
|
|
|
|
void *user_valloc(ThreadState *thr, uptr pc, uptr sz) {
|
|
|
|
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, GetPageSizeCached()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) {
|
|
|
|
uptr PageSize = GetPageSizeCached();
|
2017-08-03 06:47:54 +08:00
|
|
|
if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) {
|
|
|
|
errno = errno_ENOMEM;
|
[TSan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary:
Following up on and complementing D44404 and other sanitizer allocators.
Currently many allocator specific errors (OOM, for example) are reported as
a text message and CHECK(0) termination, no stack, no details, not too
helpful nor informative. To improve the situation, detailed and structured
common errors were defined and reported under the appropriate conditions.
Common tests were generalized a bit to cover a slightly different TSan
stack reporting format, extended to verify errno value and returned
pointer value check is now explicit to facilitate debugging.
Reviewers: dvyukov
Subscribers: srhines, kubamracek, delcypher, #sanitizers, llvm-commits
Differential Revision: https://reviews.llvm.org/D48087
llvm-svn: 334975
2018-06-19 04:03:31 +08:00
|
|
|
if (AllocatorMayReturnNull())
|
|
|
|
return nullptr;
|
|
|
|
GET_STACK_TRACE_FATAL(thr, pc);
|
|
|
|
ReportPvallocOverflow(sz, &stack);
|
2017-08-03 06:47:54 +08:00
|
|
|
}
|
2017-07-25 05:22:59 +08:00
|
|
|
// pvalloc(0) should allocate one page.
|
|
|
|
sz = sz ? RoundUpTo(sz, PageSize) : PageSize;
|
|
|
|
return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize));
|
2012-05-10 21:48:04 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr user_alloc_usable_size(const void *p) {
|
2013-02-25 16:43:10 +08:00
|
|
|
if (p == 0)
|
|
|
|
return 0;
|
2014-05-29 21:50:54 +08:00
|
|
|
MBlock *b = ctx->metamap.GetBlock((uptr)p);
|
2016-04-30 15:14:41 +08:00
|
|
|
if (!b)
|
|
|
|
return 0; // Not a valid pointer.
|
|
|
|
if (b->siz == 0)
|
|
|
|
return 1; // Zero-sized allocations are actually 1 byte.
|
|
|
|
return b->siz;
|
2012-05-10 21:48:04 +08:00
|
|
|
}
|
|
|
|
|
2012-09-24 21:19:47 +08:00
|
|
|
void invoke_malloc_hook(void *ptr, uptr size) {
|
|
|
|
ThreadState *thr = cur_thread();
|
2013-12-24 20:55:56 +08:00
|
|
|
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
|
2012-09-24 21:19:47 +08:00
|
|
|
return;
|
2014-07-08 01:39:31 +08:00
|
|
|
__sanitizer_malloc_hook(ptr, size);
|
2016-06-17 04:06:06 +08:00
|
|
|
RunMallocHooks(ptr, size);
|
2012-09-24 21:19:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void invoke_free_hook(void *ptr) {
|
|
|
|
ThreadState *thr = cur_thread();
|
2013-12-24 20:55:56 +08:00
|
|
|
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
|
2012-09-24 21:19:47 +08:00
|
|
|
return;
|
2014-07-08 01:39:31 +08:00
|
|
|
__sanitizer_free_hook(ptr);
|
2016-06-17 04:06:06 +08:00
|
|
|
RunFreeHooks(ptr);
|
2012-09-24 21:19:47 +08:00
|
|
|
}
|
|
|
|
|
2012-05-10 21:48:04 +08:00
|
|
|
void *internal_alloc(MBlockType typ, uptr sz) {
|
|
|
|
ThreadState *thr = cur_thread();
|
2012-06-22 19:08:55 +08:00
|
|
|
if (thr->nomalloc) {
|
|
|
|
thr->nomalloc = 0; // CHECK calls internal_malloc().
|
|
|
|
CHECK(0);
|
|
|
|
}
|
2016-04-27 20:30:48 +08:00
|
|
|
return InternalAlloc(sz, &thr->proc()->internal_alloc_cache);
|
2012-05-10 21:48:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void internal_free(void *p) {
|
|
|
|
ThreadState *thr = cur_thread();
|
2012-06-22 19:08:55 +08:00
|
|
|
if (thr->nomalloc) {
|
|
|
|
thr->nomalloc = 0; // CHECK calls internal_malloc().
|
|
|
|
CHECK(0);
|
|
|
|
}
|
2016-04-27 20:30:48 +08:00
|
|
|
InternalFree(p, &thr->proc()->internal_alloc_cache);
|
2012-05-10 21:48:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace __tsan
|
2013-01-23 20:08:03 +08:00
|
|
|
|
|
|
|
using namespace __tsan;
|
|
|
|
|
|
|
|
extern "C" {
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr __sanitizer_get_current_allocated_bytes() {
|
2014-05-28 23:22:12 +08:00
|
|
|
uptr stats[AllocatorStatCount];
|
2013-01-24 17:08:03 +08:00
|
|
|
allocator()->GetStats(stats);
|
2014-05-28 23:22:12 +08:00
|
|
|
return stats[AllocatorStatAllocated];
|
2013-01-23 20:08:03 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr __sanitizer_get_heap_size() {
|
2014-05-28 23:22:12 +08:00
|
|
|
uptr stats[AllocatorStatCount];
|
2013-01-24 17:08:03 +08:00
|
|
|
allocator()->GetStats(stats);
|
2014-05-28 23:22:12 +08:00
|
|
|
return stats[AllocatorStatMapped];
|
2013-01-23 20:08:03 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr __sanitizer_get_free_bytes() {
|
2013-01-24 22:07:19 +08:00
|
|
|
return 1;
|
2013-01-23 20:08:03 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr __sanitizer_get_unmapped_bytes() {
|
2013-01-24 22:07:19 +08:00
|
|
|
return 1;
|
2013-01-23 20:08:03 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr __sanitizer_get_estimated_allocated_size(uptr size) {
|
2013-01-23 20:08:03 +08:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
int __sanitizer_get_ownership(const void *p) {
|
2013-01-24 17:08:03 +08:00
|
|
|
return allocator()->GetBlockBegin(p) != 0;
|
2013-01-23 20:08:03 +08:00
|
|
|
}
|
|
|
|
|
2014-07-08 01:39:31 +08:00
|
|
|
uptr __sanitizer_get_allocated_size(const void *p) {
|
2014-07-02 02:01:20 +08:00
|
|
|
return user_alloc_usable_size(p);
|
2013-01-23 20:08:03 +08:00
|
|
|
}
|
2013-03-19 01:21:15 +08:00
|
|
|
|
|
|
|
void __tsan_on_thread_idle() {
|
|
|
|
ThreadState *thr = cur_thread();
|
2017-07-12 20:45:20 +08:00
|
|
|
thr->clock.ResetCached(&thr->proc()->clock_cache);
|
|
|
|
thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
|
2016-04-27 20:30:48 +08:00
|
|
|
allocator()->SwallowCache(&thr->proc()->alloc_cache);
|
|
|
|
internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache);
|
|
|
|
ctx->metamap.OnProcIdle(thr->proc());
|
2013-03-19 01:21:15 +08:00
|
|
|
}
|
2013-01-23 20:08:03 +08:00
|
|
|
} // extern "C"
|