2011-11-30 09:07:02 +08:00
|
|
|
//===-- asan_allocator.h ----------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// 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 AddressSanitizer, an address sanity checker.
|
|
|
|
//
|
2014-12-17 08:26:50 +08:00
|
|
|
// ASan-private header for asan_allocator.cc.
|
2011-11-30 09:07:02 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef ASAN_ALLOCATOR_H
|
|
|
|
#define ASAN_ALLOCATOR_H
|
|
|
|
|
2014-12-20 03:35:11 +08:00
|
|
|
#include "asan_flags.h"
|
2011-11-30 09:07:02 +08:00
|
|
|
#include "asan_internal.h"
|
|
|
|
#include "asan_interceptors.h"
|
2014-04-15 21:30:32 +08:00
|
|
|
#include "sanitizer_common/sanitizer_allocator.h"
|
2012-12-17 15:54:29 +08:00
|
|
|
#include "sanitizer_common/sanitizer_list.h"
|
2011-11-30 09:07:02 +08:00
|
|
|
|
|
|
|
namespace __asan {
|
|
|
|
|
2012-12-21 16:53:59 +08:00
|
|
|
enum AllocType {
|
|
|
|
FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc.
|
|
|
|
FROM_NEW = 2, // Memory block came from operator new.
|
|
|
|
FROM_NEW_BR = 3 // Memory block came from operator new [ ]
|
|
|
|
};
|
|
|
|
|
2011-12-01 01:33:13 +08:00
|
|
|
struct AsanChunk;
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2014-12-20 03:35:11 +08:00
|
|
|
struct AllocatorOptions {
|
|
|
|
u32 quarantine_size_mb;
|
|
|
|
u16 min_redzone;
|
|
|
|
u16 max_redzone;
|
|
|
|
u8 may_return_null;
|
|
|
|
u8 alloc_dealloc_mismatch;
|
|
|
|
|
|
|
|
void SetFrom(const Flags *f, const CommonFlags *cf);
|
2014-12-20 04:35:53 +08:00
|
|
|
void CopyTo(Flags *f, CommonFlags *cf);
|
2014-12-20 03:35:11 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
void InitializeAllocator(const AllocatorOptions &options);
|
|
|
|
void ReInitializeAllocator(const AllocatorOptions &options);
|
2014-12-20 04:35:53 +08:00
|
|
|
void GetAllocatorOptions(AllocatorOptions *options);
|
2013-01-28 16:05:47 +08:00
|
|
|
|
2012-09-18 15:38:10 +08:00
|
|
|
class AsanChunkView {
|
|
|
|
public:
|
|
|
|
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
|
[asan] Assert in __sanitizer_ptr_{sub,cmp} if one of the pointers was freed.
Summary:
This (partially) implements the check mentioned at
http://kristerw.blogspot.co.uk/2016/04/dangling-pointers-and-undefined-behavior.html
(via John Regehr)
Quoting:
"That the behavior is undefined follows from C11 6.2.4 "Storage
durations of objects"
The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists, has
a constant address, and retains its last-stored value throughout its
lifetime. If an object is referred to outside of its lifetime, the
behavior is undefined. The value of a pointer becomes indeterminate when
the object it points to (or just past) reaches the end of its lifetime.
and 7.22.3 "Memory management functions" that says that free ends the
lifetime of objects
The lifetime of an allocated object extends from the allocation until
the deallocation.
"
We can probably implement this for stack variables too, but I think this
is a good start to see if there's interest in this check.
We can also hide this behind a flag, too.
Reviewers: samsonov, kcc, rsmith, regehr
Subscribers: kubabrecka, llvm-commits
Differential Revision: http://reviews.llvm.org/D19691
llvm-svn: 268097
2016-04-30 04:37:34 +08:00
|
|
|
bool IsValid(); // Checks if AsanChunkView points to a valid allocated
|
|
|
|
// or quarantined chunk.
|
|
|
|
bool IsAllocated(); // Checks if the memory is currently allocated.
|
|
|
|
uptr Beg(); // First byte of user memory.
|
|
|
|
uptr End(); // Last byte of user memory.
|
|
|
|
uptr UsedSize(); // Size requested by the user.
|
2012-09-18 15:38:10 +08:00
|
|
|
uptr AllocTid();
|
|
|
|
uptr FreeTid();
|
2014-02-27 20:45:36 +08:00
|
|
|
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
|
2016-06-02 09:21:52 +08:00
|
|
|
u32 GetAllocStackId();
|
|
|
|
u32 GetFreeStackId();
|
2014-10-26 11:35:14 +08:00
|
|
|
StackTrace GetAllocStack();
|
|
|
|
StackTrace GetFreeStack();
|
2016-08-17 17:24:33 +08:00
|
|
|
AllocType GetAllocType();
|
2013-02-05 22:32:03 +08:00
|
|
|
bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
|
2012-12-11 17:02:36 +08:00
|
|
|
if (addr >= Beg() && (addr + access_size) <= End()) {
|
|
|
|
*offset = addr - Beg();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-02-05 22:32:03 +08:00
|
|
|
bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
|
2012-12-12 20:32:57 +08:00
|
|
|
(void)access_size;
|
2012-12-11 17:02:36 +08:00
|
|
|
if (addr < Beg()) {
|
|
|
|
*offset = Beg() - addr;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-02-05 22:32:03 +08:00
|
|
|
bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
|
2013-02-08 20:59:42 +08:00
|
|
|
if (addr + access_size > End()) {
|
2013-02-05 22:32:03 +08:00
|
|
|
*offset = addr - End();
|
2012-12-11 17:02:36 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-18 15:38:10 +08:00
|
|
|
private:
|
|
|
|
AsanChunk *const chunk_;
|
|
|
|
};
|
|
|
|
|
|
|
|
AsanChunkView FindHeapChunkByAddress(uptr address);
|
2016-08-24 02:13:51 +08:00
|
|
|
AsanChunkView FindHeapChunkByAllocBeg(uptr address);
|
2012-09-18 15:38:10 +08:00
|
|
|
|
2012-12-17 15:54:29 +08:00
|
|
|
// List of AsanChunks with total size.
|
|
|
|
class AsanChunkFifoList: public IntrusiveList<AsanChunk> {
|
2011-11-30 09:07:02 +08:00
|
|
|
public:
|
|
|
|
explicit AsanChunkFifoList(LinkerInitialized) { }
|
|
|
|
AsanChunkFifoList() { clear(); }
|
|
|
|
void Push(AsanChunk *n);
|
|
|
|
void PushList(AsanChunkFifoList *q);
|
|
|
|
AsanChunk *Pop();
|
2012-05-31 22:35:53 +08:00
|
|
|
uptr size() { return size_; }
|
2011-11-30 09:07:02 +08:00
|
|
|
void clear() {
|
2012-12-17 15:54:29 +08:00
|
|
|
IntrusiveList<AsanChunk>::clear();
|
2011-11-30 09:07:02 +08:00
|
|
|
size_ = 0;
|
|
|
|
}
|
|
|
|
private:
|
2012-05-31 22:35:53 +08:00
|
|
|
uptr size_;
|
2011-11-30 09:07:02 +08:00
|
|
|
};
|
|
|
|
|
2014-04-15 21:30:32 +08:00
|
|
|
struct AsanMapUnmapCallback {
|
|
|
|
void OnMap(uptr p, uptr size) const;
|
|
|
|
void OnUnmap(uptr p, uptr size) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
#if SANITIZER_CAN_USE_ALLOCATOR64
|
|
|
|
# if defined(__powerpc64__)
|
|
|
|
const uptr kAllocatorSpace = 0xa0000000000ULL;
|
|
|
|
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
|
2016-09-14 03:05:33 +08:00
|
|
|
typedef DefaultSizeClassMap SizeClassMap;
|
|
|
|
# elif defined(__aarch64__) && SANITIZER_ANDROID
|
|
|
|
const uptr kAllocatorSpace = 0x3000000000ULL;
|
|
|
|
const uptr kAllocatorSize = 0x2000000000ULL; // 128G.
|
|
|
|
typedef VeryCompactSizeClassMap SizeClassMap;
|
2015-08-21 02:49:40 +08:00
|
|
|
# elif defined(__aarch64__)
|
2016-09-14 03:05:33 +08:00
|
|
|
// AArch64/SANITIZER_CAN_USER_ALLOCATOR64 is only for 42-bit VMA
|
2015-08-21 02:49:40 +08:00
|
|
|
// so no need to different values for different VMA.
|
|
|
|
const uptr kAllocatorSpace = 0x10000000000ULL;
|
|
|
|
const uptr kAllocatorSize = 0x10000000000ULL; // 3T.
|
2016-09-14 03:05:33 +08:00
|
|
|
typedef DefaultSizeClassMap SizeClassMap;
|
2014-04-15 21:30:32 +08:00
|
|
|
# else
|
|
|
|
const uptr kAllocatorSpace = 0x600000000000ULL;
|
|
|
|
const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
|
|
|
|
typedef DefaultSizeClassMap SizeClassMap;
|
2016-09-14 03:05:33 +08:00
|
|
|
# endif
|
2016-08-26 04:23:08 +08:00
|
|
|
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
|
|
|
|
static const uptr kSpaceBeg = kAllocatorSpace;
|
|
|
|
static const uptr kSpaceSize = kAllocatorSize;
|
|
|
|
static const uptr kMetadataSize = 0;
|
|
|
|
typedef __asan::SizeClassMap SizeClassMap;
|
|
|
|
typedef AsanMapUnmapCallback MapUnmapCallback;
|
2016-08-26 08:06:03 +08:00
|
|
|
static const uptr kFlags = 0;
|
2016-08-26 04:23:08 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
|
2014-04-15 21:30:32 +08:00
|
|
|
#else // Fallback to SizeClassAllocator32.
|
|
|
|
static const uptr kRegionSizeLog = 20;
|
|
|
|
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
|
|
|
|
# if SANITIZER_WORDSIZE == 32
|
|
|
|
typedef FlatByteMap<kNumRegions> ByteMap;
|
|
|
|
# elif SANITIZER_WORDSIZE == 64
|
|
|
|
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
|
|
|
|
# endif
|
|
|
|
typedef CompactSizeClassMap SizeClassMap;
|
|
|
|
typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
|
|
|
|
SizeClassMap, kRegionSizeLog,
|
|
|
|
ByteMap,
|
|
|
|
AsanMapUnmapCallback> PrimaryAllocator;
|
|
|
|
#endif // SANITIZER_CAN_USE_ALLOCATOR64
|
|
|
|
|
2015-06-27 03:18:02 +08:00
|
|
|
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
|
2014-04-15 21:30:32 +08:00
|
|
|
typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
|
|
|
|
typedef LargeMmapAllocator<AsanMapUnmapCallback> SecondaryAllocator;
|
|
|
|
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
|
2014-12-17 09:55:03 +08:00
|
|
|
SecondaryAllocator> AsanAllocator;
|
2014-04-15 21:30:32 +08:00
|
|
|
|
|
|
|
|
2011-11-30 09:07:02 +08:00
|
|
|
struct AsanThreadLocalMallocStorage {
|
2013-01-11 16:07:43 +08:00
|
|
|
uptr quarantine_cache[16];
|
2014-12-17 09:55:03 +08:00
|
|
|
AllocatorCache allocator_cache;
|
2011-11-30 09:07:02 +08:00
|
|
|
void CommitBack();
|
2013-11-27 21:22:21 +08:00
|
|
|
private:
|
|
|
|
// These objects are allocated via mmap() and are zero-initialized.
|
|
|
|
AsanThreadLocalMallocStorage() {}
|
2011-11-30 09:07:02 +08:00
|
|
|
};
|
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
|
2012-12-21 16:53:59 +08:00
|
|
|
AllocType alloc_type);
|
2014-10-26 11:35:14 +08:00
|
|
|
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type);
|
|
|
|
void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
|
2014-07-30 17:48:23 +08:00
|
|
|
AllocType alloc_type);
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2014-10-26 11:35:14 +08:00
|
|
|
void *asan_malloc(uptr size, BufferedStackTrace *stack);
|
|
|
|
void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack);
|
|
|
|
void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack);
|
|
|
|
void *asan_valloc(uptr size, BufferedStackTrace *stack);
|
|
|
|
void *asan_pvalloc(uptr size, BufferedStackTrace *stack);
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2012-05-31 22:35:53 +08:00
|
|
|
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
|
2014-10-26 11:35:14 +08:00
|
|
|
BufferedStackTrace *stack);
|
2016-03-25 04:19:48 +08:00
|
|
|
uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp);
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2012-05-31 22:35:53 +08:00
|
|
|
uptr asan_mz_size(const void *ptr);
|
2012-01-17 14:39:10 +08:00
|
|
|
void asan_mz_force_lock();
|
|
|
|
void asan_mz_force_unlock();
|
2011-11-30 09:07:02 +08:00
|
|
|
|
2012-12-27 22:09:19 +08:00
|
|
|
void PrintInternalAllocatorStats();
|
2015-01-07 07:53:32 +08:00
|
|
|
void AsanSoftRssLimitExceededCallback(bool exceeded);
|
2012-12-27 22:09:19 +08:00
|
|
|
|
2011-11-30 09:07:02 +08:00
|
|
|
} // namespace __asan
|
|
|
|
#endif // ASAN_ALLOCATOR_H
|