5d3805fca3
* ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch builtins, store max (log2 (align), 0) into uchar field instead of align into uptr field. (ubsan_expand_objsize_ifn): Use _v1 suffixed type mismatch builtins, store uchar 0 field instead of uptr 0 field. (instrument_nonnull_return): Use _v1 suffixed nonnull return builtin, instead of passing one address of struct with 2 locations pass two addresses of structs with 1 location each. * sanitizer.def (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH, BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT, BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN, BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT): Removed. (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1, BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT, BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1, BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT): New builtins. * c-c++-common/ubsan/float-cast-overflow-1.c: Drop value keyword from expected output regexps. * c-c++-common/ubsan/float-cast-overflow-2.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-3.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-4.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-5.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-6.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-8.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-9.c: Likewise. * c-c++-common/ubsan/float-cast-overflow-10.c: Likewise. * g++.dg/ubsan/float-cast-overflow-bf.C: Likewise. * gcc.dg/ubsan/float-cast-overflow-bf.c: Likewise. * g++.dg/asan/default-options-1.C (__asan_default_options): Add used attribute. * g++.dg/asan/asan_test.C: Run with ASAN_OPTIONS=handle_segv=2 in the environment. * All source files: Merge from upstream 315899. * asan/Makefile.am (nodist_saninclude_HEADERS): Add include/sanitizer/tsan_interface.h. * asan/libtool-version: Bump the libasan SONAME. * lsan/Makefile.am (sanitizer_lsan_files): Add lsan_common_mac.cc. (lsan_files): Add lsan_linux.cc, lsan_mac.cc and lsan_malloc_mac.cc. * sanitizer_common/Makefile.am (sanitizer_common_files): Add sancov_flags.cc, sanitizer_allocator_checks.cc, sanitizer_coverage_libcdep_new.cc, sanitizer_errno.cc, sanitizer_file.cc, sanitizer_mac_libcdep.cc and sanitizer_stoptheworld_mac.cc. Remove sanitizer_coverage_libcdep.cc and sanitizer_coverage_mapping_libcdep.cc. * tsan/Makefile.am (tsan_files): Add tsan_external.cc. * ubsan/Makefile.am (DEFS): Add -DUBSAN_CAN_USE_CXXABI=1. (ubsan_files): Add ubsan_init_standalone.cc and ubsan_signals_standalone.cc. * ubsan/libtool-version: Bump the libubsan SONAME. * asan/Makefile.in: Regenerate. * lsan/Makefile.in: Regenerate. * sanitizer_common/Makefile.in: Regenerate. * tsan/Makefile.in: Regenerate. * ubsan/Makefile.in: Regenerate. From-SVN: r253887
191 lines
5.8 KiB
C++
191 lines
5.8 KiB
C++
//===-- sanitizer_allocator_combined.h --------------------------*- C++ -*-===//
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the Sanitizer Allocator.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef SANITIZER_ALLOCATOR_H
|
|
#error This file must be included inside sanitizer_allocator.h
|
|
#endif
|
|
|
|
// This class implements a complete memory allocator by using two
|
|
// internal allocators:
|
|
// PrimaryAllocator is efficient, but may not allocate some sizes (alignments).
|
|
// When allocating 2^x bytes it should return 2^x aligned chunk.
|
|
// PrimaryAllocator is used via a local AllocatorCache.
|
|
// SecondaryAllocator can allocate anything, but is not efficient.
|
|
template <class PrimaryAllocator, class AllocatorCache,
|
|
class SecondaryAllocator> // NOLINT
|
|
class CombinedAllocator {
|
|
public:
|
|
typedef typename SecondaryAllocator::FailureHandler FailureHandler;
|
|
|
|
void InitLinkerInitialized(s32 release_to_os_interval_ms) {
|
|
primary_.Init(release_to_os_interval_ms);
|
|
secondary_.InitLinkerInitialized();
|
|
stats_.InitLinkerInitialized();
|
|
}
|
|
|
|
void Init(s32 release_to_os_interval_ms) {
|
|
primary_.Init(release_to_os_interval_ms);
|
|
secondary_.Init();
|
|
stats_.Init();
|
|
}
|
|
|
|
void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
|
|
// Returning 0 on malloc(0) may break a lot of code.
|
|
if (size == 0)
|
|
size = 1;
|
|
if (size + alignment < size)
|
|
return FailureHandler::OnBadRequest();
|
|
uptr original_size = size;
|
|
// If alignment requirements are to be fulfilled by the frontend allocator
|
|
// rather than by the primary or secondary, passing an alignment lower than
|
|
// or equal to 8 will prevent any further rounding up, as well as the later
|
|
// alignment check.
|
|
if (alignment > 8)
|
|
size = RoundUpTo(size, alignment);
|
|
// The primary allocator should return a 2^x aligned allocation when
|
|
// requested 2^x bytes, hence using the rounded up 'size' when being
|
|
// serviced by the primary (this is no longer true when the primary is
|
|
// using a non-fixed base address). The secondary takes care of the
|
|
// alignment without such requirement, and allocating 'size' would use
|
|
// extraneous memory, so we employ 'original_size'.
|
|
void *res;
|
|
if (primary_.CanAllocate(size, alignment))
|
|
res = cache->Allocate(&primary_, primary_.ClassID(size));
|
|
else
|
|
res = secondary_.Allocate(&stats_, original_size, alignment);
|
|
if (!res)
|
|
return FailureHandler::OnOOM();
|
|
if (alignment > 8)
|
|
CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
|
|
return res;
|
|
}
|
|
|
|
s32 ReleaseToOSIntervalMs() const {
|
|
return primary_.ReleaseToOSIntervalMs();
|
|
}
|
|
|
|
void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) {
|
|
primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms);
|
|
}
|
|
|
|
void Deallocate(AllocatorCache *cache, void *p) {
|
|
if (!p) return;
|
|
if (primary_.PointerIsMine(p))
|
|
cache->Deallocate(&primary_, primary_.GetSizeClass(p), p);
|
|
else
|
|
secondary_.Deallocate(&stats_, p);
|
|
}
|
|
|
|
void *Reallocate(AllocatorCache *cache, void *p, uptr new_size,
|
|
uptr alignment) {
|
|
if (!p)
|
|
return Allocate(cache, new_size, alignment);
|
|
if (!new_size) {
|
|
Deallocate(cache, p);
|
|
return nullptr;
|
|
}
|
|
CHECK(PointerIsMine(p));
|
|
uptr old_size = GetActuallyAllocatedSize(p);
|
|
uptr memcpy_size = Min(new_size, old_size);
|
|
void *new_p = Allocate(cache, new_size, alignment);
|
|
if (new_p)
|
|
internal_memcpy(new_p, p, memcpy_size);
|
|
Deallocate(cache, p);
|
|
return new_p;
|
|
}
|
|
|
|
bool PointerIsMine(void *p) {
|
|
if (primary_.PointerIsMine(p))
|
|
return true;
|
|
return secondary_.PointerIsMine(p);
|
|
}
|
|
|
|
bool FromPrimary(void *p) {
|
|
return primary_.PointerIsMine(p);
|
|
}
|
|
|
|
void *GetMetaData(const void *p) {
|
|
if (primary_.PointerIsMine(p))
|
|
return primary_.GetMetaData(p);
|
|
return secondary_.GetMetaData(p);
|
|
}
|
|
|
|
void *GetBlockBegin(const void *p) {
|
|
if (primary_.PointerIsMine(p))
|
|
return primary_.GetBlockBegin(p);
|
|
return secondary_.GetBlockBegin(p);
|
|
}
|
|
|
|
// This function does the same as GetBlockBegin, but is much faster.
|
|
// Must be called with the allocator locked.
|
|
void *GetBlockBeginFastLocked(void *p) {
|
|
if (primary_.PointerIsMine(p))
|
|
return primary_.GetBlockBegin(p);
|
|
return secondary_.GetBlockBeginFastLocked(p);
|
|
}
|
|
|
|
uptr GetActuallyAllocatedSize(void *p) {
|
|
if (primary_.PointerIsMine(p))
|
|
return primary_.GetActuallyAllocatedSize(p);
|
|
return secondary_.GetActuallyAllocatedSize(p);
|
|
}
|
|
|
|
uptr TotalMemoryUsed() {
|
|
return primary_.TotalMemoryUsed() + secondary_.TotalMemoryUsed();
|
|
}
|
|
|
|
void TestOnlyUnmap() { primary_.TestOnlyUnmap(); }
|
|
|
|
void InitCache(AllocatorCache *cache) {
|
|
cache->Init(&stats_);
|
|
}
|
|
|
|
void DestroyCache(AllocatorCache *cache) {
|
|
cache->Destroy(&primary_, &stats_);
|
|
}
|
|
|
|
void SwallowCache(AllocatorCache *cache) {
|
|
cache->Drain(&primary_);
|
|
}
|
|
|
|
void GetStats(AllocatorStatCounters s) const {
|
|
stats_.Get(s);
|
|
}
|
|
|
|
void PrintStats() {
|
|
primary_.PrintStats();
|
|
secondary_.PrintStats();
|
|
}
|
|
|
|
// ForceLock() and ForceUnlock() are needed to implement Darwin malloc zone
|
|
// introspection API.
|
|
void ForceLock() {
|
|
primary_.ForceLock();
|
|
secondary_.ForceLock();
|
|
}
|
|
|
|
void ForceUnlock() {
|
|
secondary_.ForceUnlock();
|
|
primary_.ForceUnlock();
|
|
}
|
|
|
|
// Iterate over all existing chunks.
|
|
// The allocator must be locked when calling this function.
|
|
void ForEachChunk(ForEachChunkCallback callback, void *arg) {
|
|
primary_.ForEachChunk(callback, arg);
|
|
secondary_.ForEachChunk(callback, arg);
|
|
}
|
|
|
|
private:
|
|
PrimaryAllocator primary_;
|
|
SecondaryAllocator secondary_;
|
|
AllocatorGlobalStats stats_;
|
|
};
|