# Setup default compiler flags used with -fsanitize=memory option.
clang_cflags = [config.target_cflags] + config.debug_info_flags
clang_cxxflags = config.cxx_mode_flags + clang_cflags
-clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls"] + clang_cflags
+clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-generate-tags-with-calls",
+ "-mllvm", "-hwasan-allow-ifunc"] + clang_cflags
clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags
def build_invocation(compile_flags):
cl::desc("inline all checks"),
cl::Hidden, cl::init(false));
+static cl::opt<bool> ClAllowIfunc("hwasan-allow-ifunc",
+ cl::desc("allow the use of ifunc"),
+ cl::Hidden, cl::init(false));
+
namespace {
/// An instrumentation pass implementing detection of addressability bugs
void initializeCallbacks(Module &M);
+ Value *getDynamicShadowIfunc(IRBuilder<> &IRB);
Value *getDynamicShadowNonTls(IRBuilder<> &IRB);
void untagPointerOperand(Instruction *I, Value *Addr);
HwasanGenerateTagFunc = checkSanitizerInterfaceFunction(
M.getOrInsertFunction("__hwasan_generate_tag", Int8Ty));
- if (Mapping.InGlobal)
- ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
- ArrayType::get(IRB.getInt8Ty(), 0));
+ ShadowGlobal = M.getOrInsertGlobal("__hwasan_shadow",
+ ArrayType::get(IRB.getInt8Ty(), 0));
const std::string MemIntrinCallbackPrefix =
CompileKernel ? std::string("") : ClMemoryAccessCallbackPrefix;
M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy()));
}
+Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) {
+ // An empty inline asm with input reg == output reg.
+ // An opaque no-op cast, basically.
+ InlineAsm *Asm = InlineAsm::get(
+ FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
+ StringRef(""), StringRef("=r,0"),
+ /*hasSideEffects=*/false);
+ return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
+}
+
Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) {
// Generate code only when dynamic addressing is needed.
if (Mapping.Offset != kDynamicShadowSentinel)
return nullptr;
if (Mapping.InGlobal) {
- // An empty inline asm with input reg == output reg.
- // An opaque no-op cast, basically.
- InlineAsm *Asm = InlineAsm::get(
- FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false),
- StringRef(""), StringRef("=r,0"),
- /*hasSideEffects=*/false);
- return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow");
+ return getDynamicShadowIfunc(IRB);
} else {
Value *GlobalDynamicAddress =
IRB.GetInsertBlock()->getParent()->getParent()->getOrInsertGlobal(
if (!Mapping.InTls)
return getDynamicShadowNonTls(IRB);
+ if (ClAllowIfunc && !WithFrameRecord && TargetTriple.isAndroid())
+ return getDynamicShadowIfunc(IRB);
+
Value *SlotPtr = getHwasanThreadSlotPtr(IRB, IntptrTy);
assert(SlotPtr);
-; RUN: opt -S -hwasan < %s | FileCheck %s
+; RUN: opt -S -hwasan -hwasan-allow-ifunc < %s | FileCheck %s
-target triple = "x86_64-unknown-linux-gnu"
+target triple = "aarch64--linux-android"
declare void @bar([16 x i32]* %p)
-define void @foo() sanitize_hwaddress "hwasan-abi"="interceptor" {
- ; CHECK: [[LOAD:%[^ ]*]] = load i64, i64* @__hwasan_tls
+define void @alloca() sanitize_hwaddress "hwasan-abi"="interceptor" {
+ ; CHECK: [[A:%[^ ]*]] = call i8* @llvm.thread.pointer()
+ ; CHECK: [[B:%[^ ]*]] = getelementptr i8, i8* [[A]], i32 48
+ ; CHECK: [[C:%[^ ]*]] = bitcast i8* [[B]] to i64*
+ ; CHECK: [[LOAD:%[^ ]*]] = load i64, i64* [[C]]
; CHECK: [[ICMP:%[^ ]*]] = icmp eq i64 [[LOAD]], 0
; CHECK: br i1 [[ICMP]], label %[[INIT:[^,]*]], label %[[CONT:[^,]*]], !prof [[PROF:![0-9]+]]
; CHECK: [[INIT]]:
; CHECK: call void @__hwasan_thread_enter()
- ; CHECK: [[RELOAD:%[^ ]*]] = load i64, i64* @__hwasan_tls
+ ; CHECK: [[RELOAD:%[^ ]*]] = load i64, i64* [[C]]
; CHECK: br label %[[CONT]]
; CHECK: [[CONT]]:
ret void
}
+define i32 @load(i32* %p) sanitize_hwaddress "hwasan-abi"="interceptor" {
+ ; CHECK: [[SHADOW:%[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow)
+ ; CHECK-NOT: icmp
+ ; CHECK: call void @llvm.hwasan.check.memaccess(i8* [[SHADOW]],
+ %v = load i32, i32* %p
+ ret i32 %v
+}
+
; CHECK: [[PROF]] = !{!"branch_weights", i32 1, i32 100000}
; Test -hwasan-with-ifunc flag.
;
-; RUN: opt -hwasan -S < %s | \
-; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-HISTORY
-; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=1 < %s | \
-; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-HISTORY
-; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=0 < %s | \
-; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-TLS,CHECK-NOHISTORY
-; RUN: opt -hwasan -S -hwasan-with-ifunc=0 -hwasan-with-tls=0 < %s | \
+; RUN: opt -hwasan -hwasan-allow-ifunc -S < %s | \
+; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-TLS,CHECK-HISTORY
+; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=1 < %s | \
+; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-TLS,CHECK-HISTORY
+; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=1 -hwasan-record-stack-history=0 < %s | \
+; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-NOGLOBAL,CHECK-IFUNC,CHECK-NOHISTORY
+; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=0 -hwasan-with-tls=0 < %s | \
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-GLOBAL,CHECK-NOHISTORY
-; RUN: opt -hwasan -S -hwasan-with-ifunc=1 -hwasan-with-tls=0 < %s | \
-; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-IFUNC,CHECK-NOHISTORY
+; RUN: opt -hwasan -hwasan-allow-ifunc -S -hwasan-with-ifunc=1 -hwasan-with-tls=0 < %s | \
+; RUN: FileCheck %s --check-prefixes=CHECK,CHECk-NOGLOBAL,CHECK-IFUNC,CHECK-NOHISTORY
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64--linux-android22"
; CHECK-LABEL: @test_load
; CHECK: entry:
-; CHECK-IFUNC: %[[A:[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow)
-; CHECK-IFUNC: @llvm.hwasan.check.memaccess(i8* %[[A]]
+; CHECK-NOGLOBAL: %[[A:[^ ]*]] = call i8* asm "", "=r,0"([0 x i8]* @__hwasan_shadow)
+; CHECK-NOGLOBAL: @llvm.hwasan.check.memaccess(i8* %[[A]]
; CHECK-GLOBAL: load i8*, i8** @__hwasan_shadow_memory_dynamic_address
-; CHECK-TLS: %[[A:[^ ]*]] = call i8* @llvm.thread.pointer()
-; CHECK-TLS: %[[B:[^ ]*]] = getelementptr i8, i8* %[[A]], i32 48
-; CHECK-TLS: %[[C:[^ ]*]] = bitcast i8* %[[B]] to i64*
-; CHECK-TLS: %[[D:[^ ]*]] = load i64, i64* %[[C]]
-; CHECK-TLS: %[[E:[^ ]*]] = or i64 %[[D]], 4294967295
-; CHECK-TLS: = add i64 %[[E]], 1
-
; "store i64" is only used to update stack history (this input IR intentionally does not use any i64)
; W/o any allocas, the history is not updated, even if it is enabled explicitly with -hwasan-record-stack-history=1
; CHECK-NOT: store i64