[asan] Use dynamic shadow on 32-bit Android.
Summary: The following kernel change has moved ET_DYN base to 0x4000000 on arm32: https://marc.info/?l=linux-kernel&m=149825162606848&w=2 Switch to dynamic shadow base to avoid such conflicts in the future. Reserve shadow memory in an ifunc resolver, but don't use it in the instrumentation until PR35221 is fixed. This will eventually let use save one load per function. Reviewers: kcc Subscribers: aemerson, srhines, kubamracek, kristof.beyls, hiraditya, llvm-commits Differential Revision: https://reviews.llvm.org/D39393 llvm-svn: 317943
This commit is contained in:
parent
ba664c1d04
commit
989299c42b
|
@ -21,6 +21,7 @@ set(ASAN_SOURCES
|
||||||
asan_memory_profile.cc
|
asan_memory_profile.cc
|
||||||
asan_poisoning.cc
|
asan_poisoning.cc
|
||||||
asan_posix.cc
|
asan_posix.cc
|
||||||
|
asan_premap_shadow.cc
|
||||||
asan_report.cc
|
asan_report.cc
|
||||||
asan_rtl.cc
|
asan_rtl.cc
|
||||||
asan_shadow_setup.cc
|
asan_shadow_setup.cc
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#ifndef ASAN_INIT_VERSION_H
|
#ifndef ASAN_INIT_VERSION_H
|
||||||
#define ASAN_INIT_VERSION_H
|
#define ASAN_INIT_VERSION_H
|
||||||
|
|
||||||
|
#include "sanitizer_common/sanitizer_platform.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// Every time the ASan ABI changes we also change the version number in the
|
// Every time the ASan ABI changes we also change the version number in the
|
||||||
// __asan_init function name. Objects built with incompatible ASan ABI
|
// __asan_init function name. Objects built with incompatible ASan ABI
|
||||||
|
@ -32,7 +34,12 @@ extern "C" {
|
||||||
// v6=>v7: added 'odr_indicator' to __asan_global
|
// v6=>v7: added 'odr_indicator' to __asan_global
|
||||||
// v7=>v8: added '__asan_(un)register_image_globals' functions for dead
|
// v7=>v8: added '__asan_(un)register_image_globals' functions for dead
|
||||||
// stripping support on Mach-O platforms
|
// stripping support on Mach-O platforms
|
||||||
|
#if SANITIZER_WORDSIZE == 32 && SANITIZER_ANDROID
|
||||||
|
// v8=>v9: 32-bit Android switched to dynamic shadow
|
||||||
|
#define __asan_version_mismatch_check __asan_version_mismatch_check_v9
|
||||||
|
#else
|
||||||
#define __asan_version_mismatch_check __asan_version_mismatch_check_v8
|
#define __asan_version_mismatch_check __asan_version_mismatch_check_v8
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ASAN_INIT_VERSION_H
|
#endif // ASAN_INIT_VERSION_H
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "asan_interceptors.h"
|
#include "asan_interceptors.h"
|
||||||
#include "asan_internal.h"
|
#include "asan_internal.h"
|
||||||
|
#include "asan_premap_shadow.h"
|
||||||
#include "asan_thread.h"
|
#include "asan_thread.h"
|
||||||
#include "sanitizer_common/sanitizer_flags.h"
|
#include "sanitizer_common/sanitizer_flags.h"
|
||||||
#include "sanitizer_common/sanitizer_freebsd.h"
|
#include "sanitizer_common/sanitizer_freebsd.h"
|
||||||
|
@ -81,10 +82,37 @@ void *AsanDoesNotSupportStaticLinkage() {
|
||||||
return &_DYNAMIC; // defined in link.h
|
return &_DYNAMIC; // defined in link.h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ASAN_PREMAP_SHADOW
|
||||||
uptr FindDynamicShadowStart() {
|
uptr FindDynamicShadowStart() {
|
||||||
UNREACHABLE("FindDynamicShadowStart is not available");
|
uptr granularity = GetMmapGranularity();
|
||||||
return 0;
|
uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
|
||||||
|
uptr shadow_size = PremapShadowSize();
|
||||||
|
UnmapOrDie((void *)(shadow_start - granularity), shadow_size + granularity);
|
||||||
|
// MmapNoAccess does not touch TotalMmap, but UnmapOrDie decreases it.
|
||||||
|
// Compensate.
|
||||||
|
IncreaseTotalMmap(shadow_size + granularity);
|
||||||
|
return shadow_start;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
uptr FindDynamicShadowStart() {
|
||||||
|
uptr granularity = GetMmapGranularity();
|
||||||
|
uptr alignment = granularity * 8;
|
||||||
|
uptr left_padding = granularity;
|
||||||
|
uptr shadow_size = kHighShadowEnd + left_padding;
|
||||||
|
uptr map_size = shadow_size + alignment;
|
||||||
|
|
||||||
|
uptr map_start = (uptr)MmapNoAccess(map_size);
|
||||||
|
CHECK_NE(map_start, ~(uptr)0);
|
||||||
|
|
||||||
|
uptr shadow_start = RoundUpTo(map_start, alignment);
|
||||||
|
UnmapOrDie((void *)map_start, map_size);
|
||||||
|
// MmapNoAccess does not touch TotalMmap, but UnmapOrDie decreases it.
|
||||||
|
// Compensate.
|
||||||
|
IncreaseTotalMmap(map_size);
|
||||||
|
|
||||||
|
return shadow_start;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
|
|
|
@ -156,7 +156,7 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||||
# define SHADOW_OFFSET (0)
|
# define SHADOW_OFFSET (0)
|
||||||
#elif SANITIZER_WORDSIZE == 32
|
#elif SANITIZER_WORDSIZE == 32
|
||||||
# if SANITIZER_ANDROID
|
# if SANITIZER_ANDROID
|
||||||
# define SHADOW_OFFSET (0)
|
# define SHADOW_OFFSET __asan_shadow_memory_dynamic_address
|
||||||
# elif defined(__mips__)
|
# elif defined(__mips__)
|
||||||
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
|
# define SHADOW_OFFSET kMIPS32_ShadowOffset32
|
||||||
# elif SANITIZER_FREEBSD
|
# elif SANITIZER_FREEBSD
|
||||||
|
@ -200,6 +200,12 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if SANITIZER_ANDROID && defined(__arm__)
|
||||||
|
# define ASAN_PREMAP_SHADOW 1
|
||||||
|
#else
|
||||||
|
# define ASAN_PREMAP_SHADOW 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
|
||||||
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
|
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
//===-- asan_premap_shadow.cc ---------------------------------------------===//
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// Reserve shadow memory with an ifunc resolver.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "asan_mapping.h"
|
||||||
|
|
||||||
|
#if ASAN_PREMAP_SHADOW
|
||||||
|
|
||||||
|
#include "asan_premap_shadow.h"
|
||||||
|
#include "sanitizer_common/sanitizer_posix.h"
|
||||||
|
|
||||||
|
namespace __asan {
|
||||||
|
|
||||||
|
// The code in this file needs to run in an unrelocated binary. It may not
|
||||||
|
// access any external symbol, including its own non-hidden globals.
|
||||||
|
|
||||||
|
// Conservative upper limit.
|
||||||
|
uptr PremapShadowSize() {
|
||||||
|
return GetMaxVirtualAddress() >> SHADOW_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an address aligned to 8 pages, such that one page on the left and
|
||||||
|
// PremapShadowSize() bytes on the right of it are mapped r/o.
|
||||||
|
uptr PremapShadow() {
|
||||||
|
uptr granularity = GetMmapGranularity();
|
||||||
|
uptr alignment = granularity * 8;
|
||||||
|
uptr left_padding = granularity;
|
||||||
|
uptr shadow_size = PremapShadowSize();
|
||||||
|
uptr map_size = shadow_size + left_padding + alignment;
|
||||||
|
|
||||||
|
uptr map_start = (uptr)MmapNoAccess(map_size);
|
||||||
|
CHECK_NE(map_start, ~(uptr)0);
|
||||||
|
|
||||||
|
uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
|
||||||
|
uptr shadow_end = shadow_start + shadow_size;
|
||||||
|
internal_munmap(reinterpret_cast<void *>(map_start),
|
||||||
|
shadow_start - left_padding - map_start);
|
||||||
|
internal_munmap(reinterpret_cast<void *>(shadow_end),
|
||||||
|
map_start + map_size - shadow_end);
|
||||||
|
return shadow_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __asan
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
decltype(__asan_shadow)* __asan_premap_shadow() {
|
||||||
|
// The resolver may be called multiple times. Map the shadow just once.
|
||||||
|
static uptr premapped_shadow = 0;
|
||||||
|
if (!premapped_shadow) premapped_shadow = __asan::PremapShadow();
|
||||||
|
return reinterpret_cast<decltype(__asan_shadow)*>(premapped_shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// __asan_shadow is a "function" that has the same address as the first byte of
|
||||||
|
// the shadow mapping.
|
||||||
|
INTERFACE_ATTRIBUTE __attribute__((ifunc("__asan_premap_shadow"))) void
|
||||||
|
__asan_shadow();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASAN_PREMAP_SHADOW
|
|
@ -0,0 +1,28 @@
|
||||||
|
//===-- asan_mapping.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.
|
||||||
|
//
|
||||||
|
// Premap shadow range with an ifunc resolver.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ASAN_PREMAP_SHADOW_H
|
||||||
|
#define ASAN_PREMAP_SHADOW_H
|
||||||
|
|
||||||
|
#if ASAN_PREMAP_SHADOW
|
||||||
|
namespace __asan {
|
||||||
|
// Conservative upper limit.
|
||||||
|
uptr PremapShadowSize();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" INTERFACE_ATTRIBUTE void __asan_shadow();
|
||||||
|
|
||||||
|
#endif // ASAN_PREMAP_SHADOW_H
|
|
@ -73,6 +73,7 @@ INLINE uptr GetPageSizeCached() {
|
||||||
return PageSizeCached;
|
return PageSizeCached;
|
||||||
}
|
}
|
||||||
uptr GetMmapGranularity();
|
uptr GetMmapGranularity();
|
||||||
|
uptr GetMaxVirtualAddress();
|
||||||
uptr GetMaxUserVirtualAddress();
|
uptr GetMaxUserVirtualAddress();
|
||||||
// Threads
|
// Threads
|
||||||
tid_t GetTid();
|
tid_t GetTid();
|
||||||
|
|
|
@ -34,7 +34,9 @@ struct CommonFlags {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Functions to get/set global CommonFlags shared by all sanitizer runtimes:
|
// Functions to get/set global CommonFlags shared by all sanitizer runtimes:
|
||||||
extern CommonFlags common_flags_dont_use;
|
// FIXME: hidden needed for asan_premap_shadow. Consider building with
|
||||||
|
// -fvisibility=hidden.
|
||||||
|
extern CommonFlags common_flags_dont_use __attribute__((visibility("hidden")));
|
||||||
inline const CommonFlags *common_flags() {
|
inline const CommonFlags *common_flags() {
|
||||||
return &common_flags_dont_use;
|
return &common_flags_dont_use;
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,10 @@ uptr GetMaxUserVirtualAddress() {
|
||||||
return ShadowBounds.memory_limit - 1;
|
return ShadowBounds.memory_limit - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr GetMaxVirtualAddress() {
|
||||||
|
return GetMaxUserVirtualAddress();
|
||||||
|
}
|
||||||
|
|
||||||
static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
|
static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
|
||||||
bool raw_report, bool die_for_nomem) {
|
bool raw_report, bool die_for_nomem) {
|
||||||
size = RoundUpTo(size, PAGE_SIZE);
|
size = RoundUpTo(size, PAGE_SIZE);
|
||||||
|
|
|
@ -954,7 +954,7 @@ static uptr GetKernelAreaSize() {
|
||||||
}
|
}
|
||||||
#endif // SANITIZER_WORDSIZE == 32
|
#endif // SANITIZER_WORDSIZE == 32
|
||||||
|
|
||||||
uptr GetMaxUserVirtualAddress() {
|
uptr GetMaxVirtualAddress() {
|
||||||
#if SANITIZER_NETBSD && defined(__x86_64__)
|
#if SANITIZER_NETBSD && defined(__x86_64__)
|
||||||
return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE)
|
return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE)
|
||||||
#elif SANITIZER_WORDSIZE == 64
|
#elif SANITIZER_WORDSIZE == 64
|
||||||
|
@ -978,15 +978,21 @@ uptr GetMaxUserVirtualAddress() {
|
||||||
# if defined(__s390__)
|
# if defined(__s390__)
|
||||||
return (1ULL << 31) - 1; // 0x7fffffff;
|
return (1ULL << 31) - 1; // 0x7fffffff;
|
||||||
# else
|
# else
|
||||||
uptr res = (1ULL << 32) - 1; // 0xffffffff;
|
return (1ULL << 32) - 1; // 0xffffffff;
|
||||||
if (!common_flags()->full_address_space)
|
|
||||||
res -= GetKernelAreaSize();
|
|
||||||
CHECK_LT(reinterpret_cast<uptr>(&res), res);
|
|
||||||
return res;
|
|
||||||
# endif
|
# endif
|
||||||
#endif // SANITIZER_WORDSIZE
|
#endif // SANITIZER_WORDSIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr GetMaxUserVirtualAddress() {
|
||||||
|
uptr addr = GetMaxVirtualAddress();
|
||||||
|
#if SANITIZER_WORDSIZE == 32 && !defined(__s390__)
|
||||||
|
if (!common_flags()->full_address_space)
|
||||||
|
addr -= GetKernelAreaSize();
|
||||||
|
CHECK_LT(reinterpret_cast<uptr>(&addr), addr);
|
||||||
|
#endif
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
uptr GetPageSize() {
|
uptr GetPageSize() {
|
||||||
// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
|
// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
|
||||||
#if SANITIZER_ANDROID
|
#if SANITIZER_ANDROID
|
||||||
|
|
|
@ -864,6 +864,10 @@ uptr GetMaxUserVirtualAddress() {
|
||||||
#endif // SANITIZER_WORDSIZE
|
#endif // SANITIZER_WORDSIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr GetMaxVirtualAddress() {
|
||||||
|
return GetMaxUserVirtualAddress();
|
||||||
|
}
|
||||||
|
|
||||||
uptr FindAvailableMemoryRange(uptr shadow_size,
|
uptr FindAvailableMemoryRange(uptr shadow_size,
|
||||||
uptr alignment,
|
uptr alignment,
|
||||||
uptr left_padding,
|
uptr left_padding,
|
||||||
|
|
|
@ -70,6 +70,10 @@ uptr GetMaxUserVirtualAddress() {
|
||||||
return (uptr)si.lpMaximumApplicationAddress;
|
return (uptr)si.lpMaximumApplicationAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uptr GetMaxVirtualAddress() {
|
||||||
|
return GetMaxUserVirtualAddress();
|
||||||
|
}
|
||||||
|
|
||||||
bool FileExists(const char *filename) {
|
bool FileExists(const char *filename) {
|
||||||
return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES;
|
return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,8 +136,8 @@ static const char *const kAsanUnregisterElfGlobalsName =
|
||||||
static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
|
static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init";
|
||||||
static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
|
static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init";
|
||||||
static const char *const kAsanInitName = "__asan_init";
|
static const char *const kAsanInitName = "__asan_init";
|
||||||
static const char *const kAsanVersionCheckName =
|
static const char *const kAsanVersionCheckNamePrefix =
|
||||||
"__asan_version_mismatch_check_v8";
|
"__asan_version_mismatch_check_v";
|
||||||
static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
|
static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp";
|
||||||
static const char *const kAsanPtrSub = "__sanitizer_ptr_sub";
|
static const char *const kAsanPtrSub = "__sanitizer_ptr_sub";
|
||||||
static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return";
|
static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return";
|
||||||
|
@ -207,6 +207,12 @@ static cl::opt<bool> ClForceDynamicShadow(
|
||||||
cl::desc("Load shadow address into a local variable for each function"),
|
cl::desc("Load shadow address into a local variable for each function"),
|
||||||
cl::Hidden, cl::init(false));
|
cl::Hidden, cl::init(false));
|
||||||
|
|
||||||
|
static cl::opt<bool>
|
||||||
|
ClWithIfunc("asan-with-ifunc",
|
||||||
|
cl::desc("Access dynamic shadow through an ifunc global on "
|
||||||
|
"platforms that support this"),
|
||||||
|
cl::Hidden, cl::init(false));
|
||||||
|
|
||||||
// This flag limits the number of instructions to be instrumented
|
// This flag limits the number of instructions to be instrumented
|
||||||
// in any given BB. Normally, this should be set to unlimited (INT_MAX),
|
// in any given BB. Normally, this should be set to unlimited (INT_MAX),
|
||||||
// but due to http://llvm.org/bugs/show_bug.cgi?id=12652 we temporary
|
// but due to http://llvm.org/bugs/show_bug.cgi?id=12652 we temporary
|
||||||
|
@ -447,10 +453,14 @@ private:
|
||||||
|
|
||||||
/// This struct defines the shadow mapping using the rule:
|
/// This struct defines the shadow mapping using the rule:
|
||||||
/// shadow = (mem >> Scale) ADD-or-OR Offset.
|
/// shadow = (mem >> Scale) ADD-or-OR Offset.
|
||||||
|
/// If InGlobal is true, then
|
||||||
|
/// extern char __asan_shadow[];
|
||||||
|
/// shadow = (mem >> Scale) + &__asan_shadow
|
||||||
struct ShadowMapping {
|
struct ShadowMapping {
|
||||||
int Scale;
|
int Scale;
|
||||||
uint64_t Offset;
|
uint64_t Offset;
|
||||||
bool OrShadowOffset;
|
bool OrShadowOffset;
|
||||||
|
bool InGlobal;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
@ -472,6 +482,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
||||||
TargetTriple.getArch() == Triple::mipsel;
|
TargetTriple.getArch() == Triple::mipsel;
|
||||||
bool IsMIPS64 = TargetTriple.getArch() == Triple::mips64 ||
|
bool IsMIPS64 = TargetTriple.getArch() == Triple::mips64 ||
|
||||||
TargetTriple.getArch() == Triple::mips64el;
|
TargetTriple.getArch() == Triple::mips64el;
|
||||||
|
bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb();
|
||||||
bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64;
|
bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64;
|
||||||
bool IsWindows = TargetTriple.isOSWindows();
|
bool IsWindows = TargetTriple.isOSWindows();
|
||||||
bool IsFuchsia = TargetTriple.isOSFuchsia();
|
bool IsFuchsia = TargetTriple.isOSFuchsia();
|
||||||
|
@ -479,10 +490,8 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
||||||
ShadowMapping Mapping;
|
ShadowMapping Mapping;
|
||||||
|
|
||||||
if (LongSize == 32) {
|
if (LongSize == 32) {
|
||||||
// Android is always PIE, which means that the beginning of the address
|
|
||||||
// space is always available.
|
|
||||||
if (IsAndroid)
|
if (IsAndroid)
|
||||||
Mapping.Offset = 0;
|
Mapping.Offset = kDynamicShadowSentinel;
|
||||||
else if (IsMIPS32)
|
else if (IsMIPS32)
|
||||||
Mapping.Offset = kMIPS32_ShadowOffset32;
|
Mapping.Offset = kMIPS32_ShadowOffset32;
|
||||||
else if (IsFreeBSD)
|
else if (IsFreeBSD)
|
||||||
|
@ -550,6 +559,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize,
|
||||||
Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU &&
|
Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU &&
|
||||||
!(Mapping.Offset & (Mapping.Offset - 1)) &&
|
!(Mapping.Offset & (Mapping.Offset - 1)) &&
|
||||||
Mapping.Offset != kDynamicShadowSentinel;
|
Mapping.Offset != kDynamicShadowSentinel;
|
||||||
|
Mapping.InGlobal = ClWithIfunc && IsAndroid && IsArmOrThumb;
|
||||||
|
|
||||||
return Mapping;
|
return Mapping;
|
||||||
}
|
}
|
||||||
|
@ -672,6 +682,7 @@ private:
|
||||||
DominatorTree *DT;
|
DominatorTree *DT;
|
||||||
Function *AsanHandleNoReturnFunc;
|
Function *AsanHandleNoReturnFunc;
|
||||||
Function *AsanPtrCmpFunction, *AsanPtrSubFunction;
|
Function *AsanPtrCmpFunction, *AsanPtrSubFunction;
|
||||||
|
Constant *AsanShadowGlobal;
|
||||||
|
|
||||||
// These arrays is indexed by AccessIsWrite, Experiment and log2(AccessSize).
|
// These arrays is indexed by AccessIsWrite, Experiment and log2(AccessSize).
|
||||||
Function *AsanErrorCallback[2][2][kNumberOfAccessSizes];
|
Function *AsanErrorCallback[2][2][kNumberOfAccessSizes];
|
||||||
|
@ -744,6 +755,7 @@ private:
|
||||||
size_t MinRedzoneSizeForGlobal() const {
|
size_t MinRedzoneSizeForGlobal() const {
|
||||||
return RedzoneSizeForScale(Mapping.Scale);
|
return RedzoneSizeForScale(Mapping.Scale);
|
||||||
}
|
}
|
||||||
|
int GetAsanVersion(const Module &M) const;
|
||||||
|
|
||||||
GlobalsMetadata GlobalsMD;
|
GlobalsMetadata GlobalsMD;
|
||||||
bool CompileKernel;
|
bool CompileKernel;
|
||||||
|
@ -1109,6 +1121,11 @@ Value *AddressSanitizer::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
|
||||||
if (Mapping.Offset == 0) return Shadow;
|
if (Mapping.Offset == 0) return Shadow;
|
||||||
// (Shadow >> scale) | offset
|
// (Shadow >> scale) | offset
|
||||||
Value *ShadowBase;
|
Value *ShadowBase;
|
||||||
|
if (Mapping.InGlobal)
|
||||||
|
return IRB.CreatePtrToInt(
|
||||||
|
IRB.CreateGEP(AsanShadowGlobal,
|
||||||
|
{ConstantInt::get(IntptrTy, 0), Shadow}),
|
||||||
|
IntptrTy);
|
||||||
if (LocalDynamicShadow)
|
if (LocalDynamicShadow)
|
||||||
ShadowBase = LocalDynamicShadow;
|
ShadowBase = LocalDynamicShadow;
|
||||||
else
|
else
|
||||||
|
@ -2156,6 +2173,16 @@ bool AddressSanitizerModule::InstrumentGlobals(IRBuilder<> &IRB, Module &M, bool
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AddressSanitizerModule::GetAsanVersion(const Module &M) const {
|
||||||
|
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
||||||
|
bool isAndroid = Triple(M.getTargetTriple()).isAndroid();
|
||||||
|
int Version = 8;
|
||||||
|
// 32-bit Android is one version ahead because of the switch to dynamic
|
||||||
|
// shadow.
|
||||||
|
Version += (LongSize == 32 && isAndroid);
|
||||||
|
return Version;
|
||||||
|
}
|
||||||
|
|
||||||
bool AddressSanitizerModule::runOnModule(Module &M) {
|
bool AddressSanitizerModule::runOnModule(Module &M) {
|
||||||
C = &(M.getContext());
|
C = &(M.getContext());
|
||||||
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
int LongSize = M.getDataLayout().getPointerSizeInBits();
|
||||||
|
@ -2169,9 +2196,11 @@ bool AddressSanitizerModule::runOnModule(Module &M) {
|
||||||
|
|
||||||
// Create a module constructor. A destructor is created lazily because not all
|
// Create a module constructor. A destructor is created lazily because not all
|
||||||
// platforms, and not all modules need it.
|
// platforms, and not all modules need it.
|
||||||
|
std::string VersionCheckName =
|
||||||
|
kAsanVersionCheckNamePrefix + std::to_string(GetAsanVersion(M));
|
||||||
std::tie(AsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
|
std::tie(AsanCtorFunction, std::ignore) = createSanitizerCtorAndInitFunctions(
|
||||||
M, kAsanModuleCtorName, kAsanInitName, /*InitArgTypes=*/{},
|
M, kAsanModuleCtorName, kAsanInitName, /*InitArgTypes=*/{},
|
||||||
/*InitArgs=*/{}, kAsanVersionCheckName);
|
/*InitArgs=*/{}, VersionCheckName);
|
||||||
|
|
||||||
bool CtorComdat = true;
|
bool CtorComdat = true;
|
||||||
bool Changed = false;
|
bool Changed = false;
|
||||||
|
@ -2270,6 +2299,9 @@ void AddressSanitizer::initializeCallbacks(Module &M) {
|
||||||
EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false),
|
EmptyAsm = InlineAsm::get(FunctionType::get(IRB.getVoidTy(), false),
|
||||||
StringRef(""), StringRef(""),
|
StringRef(""), StringRef(""),
|
||||||
/*hasSideEffects=*/true);
|
/*hasSideEffects=*/true);
|
||||||
|
if (Mapping.InGlobal)
|
||||||
|
AsanShadowGlobal = M.getOrInsertGlobal("__asan_shadow",
|
||||||
|
ArrayType::get(IRB.getInt8Ty(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
|
@ -2311,7 +2343,7 @@ bool AddressSanitizer::maybeInsertAsanInitAtFunctionEntry(Function &F) {
|
||||||
|
|
||||||
void AddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) {
|
void AddressSanitizer::maybeInsertDynamicShadowAtFunctionEntry(Function &F) {
|
||||||
// Generate code only when dynamic addressing is needed.
|
// Generate code only when dynamic addressing is needed.
|
||||||
if (Mapping.Offset != kDynamicShadowSentinel)
|
if (Mapping.Offset != kDynamicShadowSentinel || Mapping.InGlobal)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IRBuilder<> IRB(&F.front().front());
|
IRBuilder<> IRB(&F.front().front());
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
; Test -asan-force-dynamic-shadow flag.
|
||||||
|
;
|
||||||
|
; RUN: opt -asan -asan-module -S -asan-with-ifunc=1 < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC
|
||||||
|
; RUN: opt -asan -asan-module -S -asan-with-ifunc=0 < %s | FileCheck %s --check-prefixes=CHECK,CHECK-NOIFUNC
|
||||||
|
|
||||||
|
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||||
|
target triple = "armv7--linux-android"
|
||||||
|
|
||||||
|
; CHECK-IFUNC: @__asan_shadow = external global [0 x i8]
|
||||||
|
; CHECK-NOIFUNC: @__asan_shadow_memory_dynamic_address = external global i32
|
||||||
|
|
||||||
|
define i32 @test_load(i32* %a) sanitize_address {
|
||||||
|
; First instrumentation in the function must be to load the dynamic shadow
|
||||||
|
; address into a local variable.
|
||||||
|
; CHECK-LABEL: @test_load
|
||||||
|
; CHECK: entry:
|
||||||
|
|
||||||
|
; CHECK-IFUNC-NEXT: %[[A:[^ ]*]] = ptrtoint i32* %a to i32
|
||||||
|
; CHECK-IFUNC-NEXT: %[[B:[^ ]*]] = lshr i32 %[[A]], 3
|
||||||
|
; CHECK-IFUNC-NEXT: %[[C:[^ ]*]] = getelementptr [0 x i8], [0 x i8]* @__asan_shadow, i32 0, i32 %[[B]]
|
||||||
|
|
||||||
|
; CHECK-NOIFUNC-NEXT: %[[SHADOW:[^ ]*]] = load i32, i32* @__asan_shadow_memory_dynamic_address
|
||||||
|
; CHECK-NOIFUNC-NEXT: %[[A:[^ ]*]] = ptrtoint i32* %a to i32
|
||||||
|
; CHECK-NOIFUNC-NEXT: %[[B:[^ ]*]] = lshr i32 %[[A]], 3
|
||||||
|
; CHECK-NOIFUNC-NEXT: %[[C:[^ ]*]] = add i32 %[[B]], %[[SHADOW]]
|
||||||
|
|
||||||
|
entry:
|
||||||
|
%x = load i32, i32* %a, align 4
|
||||||
|
ret i32 %x
|
||||||
|
}
|
Loading…
Reference in New Issue