diff --git a/compiler-rt/test/hwasan/TestCases/try-catch.cc b/compiler-rt/test/hwasan/TestCases/try-catch.cc new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/try-catch.cc @@ -0,0 +1,59 @@ +// 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 +#include + +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 frame 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. + hwasan_read(&x[0], sizeof(x)); + // GOOD: hello + printf("%s\n", e.what()); + } +} + +int main() { + f(); +} diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -157,6 +157,11 @@ cl::desc("instrument memory intrinsics"), cl::Hidden, cl::init(true)); +static cl::opt + ClInstrumentLandingPads("hwasan-instrument-landing-pads", + cl::desc("instrument landing pads"), cl::Hidden, + cl::init(true)); + static cl::opt ClInlineAllChecks("hwasan-inline-all-checks", cl::desc("inline all checks"), cl::Hidden, cl::init(false)); @@ -202,6 +207,7 @@ Value *untagPointer(IRBuilder<> &IRB, Value *PtrLong); bool instrumentStack(SmallVectorImpl &Allocas, SmallVectorImpl &RetVec, Value *StackTag); + bool instrumentLandingPads(SmallVectorImpl &RetVec); Value *getNextTagWithCall(IRBuilder<> &IRB); Value *getStackBaseTag(IRBuilder<> &IRB); Value *getAllocaTag(IRBuilder<> &IRB, Value *StackTag, AllocaInst *AI, @@ -216,6 +222,7 @@ 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. @@ -440,6 +447,9 @@ IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IRB.getInt32Ty(), IntptrTy); + HWAsanHandleVfork = + M.getOrInsertFunction("__hwasan_handle_vfork", IRB.getVoidTy(), IntptrTy); + HwasanThreadEnterFunc = M.getOrInsertFunction("__hwasan_thread_enter", IRB.getVoidTy()); } @@ -955,6 +965,23 @@ return ShadowBase; } +bool HWAddressSanitizer::instrumentLandingPads( + SmallVectorImpl &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 &Allocas, SmallVectorImpl &RetVec, Value *StackTag) { @@ -1023,6 +1050,7 @@ SmallVector ToInstrument; SmallVector AllocasToInstrument; SmallVector RetVec; + SmallVector LandingPadVec; for (auto &BB : F) { for (auto &Inst : BB) { if (ClInstrumentStack) @@ -1041,6 +1069,9 @@ isa(Inst)) RetVec.push_back(&Inst); + if (ClInstrumentLandingPads && isa(Inst)) + LandingPadVec.push_back(&Inst); + Value *MaybeMask = nullptr; bool IsWrite; unsigned Alignment; @@ -1052,13 +1083,17 @@ } } + 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);