Skip to content

Commit

Permalink
HWASan exception support.
Browse files Browse the repository at this point in the history
Summary:
Adds a call to __hwasan_handle_vfork(SP) at each landingpad entry.

Reusing __hwasan_handle_vfork instead of introducing a new runtime call
in order to be ABI-compatible with old runtime library.

Reviewers: pcc

Subscribers: kubamracek, hiraditya, #sanitizers, llvm-commits

Tags: #sanitizers, #llvm

Differential Revision: https://reviews.llvm.org/D61968

llvm-svn: 360959
  • Loading branch information
eugenis committed May 16, 2019
1 parent 627e383 commit 7f281b2
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 1 deletion.
60 changes: 60 additions & 0 deletions compiler-rt/test/hwasan/TestCases/try-catch.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: %clangxx_hwasan %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=GOOD
// RUN: %clangxx_hwasan %s -mllvm -hwasan-instrument-landing-pads=0 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=BAD

#include <stdexcept>
#include <cstdio>

static void optimization_barrier(void* arg) {
asm volatile("" : : "r"(arg) : "memory");
}

__attribute__((noinline))
void h() {
char x[1000];
optimization_barrier(x);
throw std::runtime_error("hello");
}

__attribute__((noinline))
void g() {
char x[1000];
optimization_barrier(x);
h();
optimization_barrier(x);
}

__attribute__((noinline))
void hwasan_read(char *p, int size) {
char volatile sink;
for (int i = 0; i < size; ++i)
sink = p[i];
}

__attribute__((noinline, no_sanitize("hwaddress"))) void after_catch() {
char x[10000];
hwasan_read(&x[0], sizeof(x));
}


__attribute__((noinline))
void f() {
char x[1000];
try {
// Put two tagged frames on the stack, throw an exception from the deepest one.
g();
} catch (const std::runtime_error &e) {
// Put an untagged frame on stack, check that it is indeed untagged.
// This relies on exception support zeroing out stack tags.
// BAD: tag-mismatch
after_catch();
// Check that an in-scope stack allocation is still tagged.
// This relies on exception support not zeroing too much.
hwasan_read(&x[0], sizeof(x));
// GOOD: hello
printf("%s\n", e.what());
}
}

int main() {
f();
}
37 changes: 36 additions & 1 deletion llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ static cl::opt<bool>
cl::desc("instrument memory intrinsics"),
cl::Hidden, cl::init(true));

static cl::opt<bool>
ClInstrumentLandingPads("hwasan-instrument-landing-pads",
cl::desc("instrument landing pads"), cl::Hidden,
cl::init(true));

static cl::opt<bool> ClInlineAllChecks("hwasan-inline-all-checks",
cl::desc("inline all checks"),
cl::Hidden, cl::init(false));
Expand Down Expand Up @@ -202,6 +207,7 @@ class HWAddressSanitizer {
Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong);
bool instrumentStack(SmallVectorImpl<AllocaInst *> &Allocas,
SmallVectorImpl<Instruction *> &RetVec, Value *StackTag);
bool instrumentLandingPads(SmallVectorImpl<Instruction *> &RetVec);
Value *getNextTagWithCall(IRBuilder<> &IRB);
Value *getStackBaseTag(IRBuilder<> &IRB);
Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI,
Expand All @@ -216,6 +222,7 @@ class HWAddressSanitizer {
std::string CurModuleUniqueId;
Triple TargetTriple;
FunctionCallee HWAsanMemmove, HWAsanMemcpy, HWAsanMemset;
FunctionCallee HWAsanHandleVfork;

// Frame description is a way to pass names/sizes of local variables
// to the run-time w/o adding extra executable code in every function.
Expand Down Expand Up @@ -440,6 +447,9 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) {
IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
IRB.getInt32Ty(), IntptrTy);

HWAsanHandleVfork =
M.getOrInsertFunction("__hwasan_handle_vfork", IRB.getVoidTy(), IntptrTy);

HwasanThreadEnterFunc =
M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy());
}
Expand Down Expand Up @@ -955,6 +965,23 @@ Value *HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB,
return ShadowBase;
}

bool HWAddressSanitizer::instrumentLandingPads(
SmallVectorImpl<Instruction *> &LandingPadVec) {
Module *M = LandingPadVec[0]->getModule();
Function *ReadRegister =
Intrinsic::getDeclaration(M, Intrinsic::read_register, IntptrTy);
const char *RegName =
(TargetTriple.getArch() == Triple::x86_64) ? "rsp" : "sp";
MDNode *MD = MDNode::get(*C, {MDString::get(*C, RegName)});
Value *Args[] = {MetadataAsValue::get(*C, MD)};

for (auto *LP : LandingPadVec) {
IRBuilder<> IRB(LP->getNextNode());
IRB.CreateCall(HWAsanHandleVfork, {IRB.CreateCall(ReadRegister, Args)});
}
return true;
}

bool HWAddressSanitizer::instrumentStack(
SmallVectorImpl<AllocaInst *> &Allocas,
SmallVectorImpl<Instruction *> &RetVec, Value *StackTag) {
Expand Down Expand Up @@ -1023,6 +1050,7 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
SmallVector<Instruction*, 16> ToInstrument;
SmallVector<AllocaInst*, 8> AllocasToInstrument;
SmallVector<Instruction*, 8> RetVec;
SmallVector<Instruction*, 8> LandingPadVec;
for (auto &BB : F) {
for (auto &Inst : BB) {
if (ClInstrumentStack)
Expand All @@ -1041,6 +1069,9 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
isa<CleanupReturnInst>(Inst))
RetVec.push_back(&Inst);

if (ClInstrumentLandingPads && isa<LandingPadInst>(Inst))
LandingPadVec.push_back(&Inst);

Value *MaybeMask = nullptr;
bool IsWrite;
unsigned Alignment;
Expand All @@ -1052,13 +1083,17 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) {
}
}

initializeCallbacks(*F.getParent());

if (!LandingPadVec.empty())
instrumentLandingPads(LandingPadVec);

if (AllocasToInstrument.empty() && ToInstrument.empty())
return false;

if (ClCreateFrameDescriptions && !AllocasToInstrument.empty())
createFrameGlobal(F, createFrameString(AllocasToInstrument));

initializeCallbacks(*F.getParent());

assert(!LocalDynamicShadow);

Expand Down
37 changes: 37 additions & 0 deletions llvm/test/Instrumentation/HWAddressSanitizer/landingpad.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
; RUN: opt < %s -mtriple aarch64-linux-android -hwasan -S | FileCheck %s --check-prefixes=COMMON,ARM
; RUN: opt < %s -mtriple x86_64-linux -hwasan -S | FileCheck %s --check-prefixes=COMMON,X86

target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-android"

define i32 @f() local_unnamed_addr sanitize_hwaddress personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
entry:
invoke void @g()
to label %return unwind label %lpad

lpad:
; COMMON: landingpad { i8*, i32 }
; COMMON-NEXT: catch i8* null
%0 = landingpad { i8*, i32 }
catch i8* null

; COMMON-NEXT: %[[X:[^ ]*]] = call i64 @llvm.read_register.i64(metadata ![[META:[^ ]*]])
; COMMON-NEXT: call void @__hwasan_handle_vfork(i64 %[[X]])

%1 = extractvalue { i8*, i32 } %0, 0
%2 = tail call i8* @__cxa_begin_catch(i8* %1)
tail call void @__cxa_end_catch()
br label %return
return:
%retval.0 = phi i32 [ 1, %lpad ], [ 0, %entry ]
ret i32 %retval.0
}

declare void @g() local_unnamed_addr

declare i32 @__gxx_personality_v0(...)
declare i8* @__cxa_begin_catch(i8*) local_unnamed_addr
declare void @__cxa_end_catch() local_unnamed_addr

; ARM: ![[META]] = !{!"sp"}
; X86: ![[META]] = !{!"rsp"}

0 comments on commit 7f281b2

Please sign in to comment.