mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[hwasan] Use stack safety analysis.
This avoids unnecessary instrumentation. Reviewed By: eugenis, vitalybuka Differential Revision: https://reviews.llvm.org/D105703
This commit is contained in:
parent
cbaf468075
commit
b276efa2ab
@ -25,17 +25,21 @@ namespace llvm {
|
||||
class HWAddressSanitizerPass : public PassInfoMixin<HWAddressSanitizerPass> {
|
||||
public:
|
||||
explicit HWAddressSanitizerPass(bool CompileKernel = false,
|
||||
bool Recover = false);
|
||||
bool Recover = false,
|
||||
bool DisableOptimization = false);
|
||||
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||
static bool isRequired() { return true; }
|
||||
|
||||
private:
|
||||
bool CompileKernel;
|
||||
bool Recover;
|
||||
bool DisableOptimization;
|
||||
};
|
||||
|
||||
FunctionPass *createHWAddressSanitizerLegacyPassPass(bool CompileKernel = false,
|
||||
bool Recover = false);
|
||||
FunctionPass *
|
||||
createHWAddressSanitizerLegacyPassPass(bool CompileKernel = false,
|
||||
bool Recover = false,
|
||||
bool DisableOptimization = false);
|
||||
|
||||
namespace HWASanAccessInfo {
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Analysis/StackSafetyAnalysis.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/IR/Attributes.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
@ -109,6 +110,11 @@ static cl::opt<bool> ClInstrumentStack("hwasan-instrument-stack",
|
||||
cl::desc("instrument stack (allocas)"),
|
||||
cl::Hidden, cl::init(true));
|
||||
|
||||
static cl::opt<bool>
|
||||
ClUseStackSafety("hwasan-use-stack-safety", cl::Hidden, cl::init(true),
|
||||
cl::Hidden, cl::desc("Use Stack Safety analysis results"),
|
||||
cl::Optional);
|
||||
|
||||
static cl::opt<bool> ClUARRetagToZero(
|
||||
"hwasan-uar-retag-to-zero",
|
||||
cl::desc("Clear alloca tags before returning from the function to allow "
|
||||
@ -204,11 +210,23 @@ bool shouldInstrumentWithCalls(const Triple &TargetTriple) {
|
||||
return ClInstrumentWithCalls || TargetTriple.getArch() == Triple::x86_64;
|
||||
}
|
||||
|
||||
bool mightUseStackSafetyAnalysis(bool DisableOptimization) {
|
||||
return ClUseStackSafety.getNumOccurrences() ? ClUseStackSafety
|
||||
: !DisableOptimization;
|
||||
}
|
||||
|
||||
bool shouldUseStackSafetyAnalysis(const Triple &TargetTriple,
|
||||
bool DisableOptimization) {
|
||||
return shouldInstrumentStack(TargetTriple) &&
|
||||
mightUseStackSafetyAnalysis(DisableOptimization);
|
||||
}
|
||||
/// An instrumentation pass implementing detection of addressability bugs
|
||||
/// using tagged pointers.
|
||||
class HWAddressSanitizer {
|
||||
public:
|
||||
HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover) : M(M) {
|
||||
HWAddressSanitizer(Module &M, bool CompileKernel, bool Recover,
|
||||
const StackSafetyGlobalInfo *SSI)
|
||||
: M(M), SSI(SSI) {
|
||||
this->Recover = ClRecover.getNumOccurrences() > 0 ? ClRecover : Recover;
|
||||
this->CompileKernel = ClEnableKhwasan.getNumOccurrences() > 0
|
||||
? ClEnableKhwasan
|
||||
@ -217,6 +235,8 @@ public:
|
||||
initializeModule();
|
||||
}
|
||||
|
||||
void setSSI(const StackSafetyGlobalInfo *S) { SSI = S; }
|
||||
|
||||
bool sanitizeFunction(Function &F);
|
||||
void initializeModule();
|
||||
void createHwasanCtorComdat();
|
||||
@ -269,6 +289,7 @@ public:
|
||||
private:
|
||||
LLVMContext *C;
|
||||
Module &M;
|
||||
const StackSafetyGlobalInfo *SSI;
|
||||
Triple TargetTriple;
|
||||
FunctionCallee HWAsanMemmove, HWAsanMemcpy, HWAsanMemset;
|
||||
FunctionCallee HWAsanHandleVfork;
|
||||
@ -339,7 +360,8 @@ public:
|
||||
static char ID;
|
||||
|
||||
explicit HWAddressSanitizerLegacyPass(bool CompileKernel = false,
|
||||
bool Recover = false)
|
||||
bool Recover = false,
|
||||
bool DisableOptimization = false)
|
||||
: FunctionPass(ID), CompileKernel(CompileKernel), Recover(Recover) {
|
||||
initializeHWAddressSanitizerLegacyPassPass(
|
||||
*PassRegistry::getPassRegistry());
|
||||
@ -348,11 +370,19 @@ public:
|
||||
StringRef getPassName() const override { return "HWAddressSanitizer"; }
|
||||
|
||||
bool doInitialization(Module &M) override {
|
||||
HWASan = std::make_unique<HWAddressSanitizer>(M, CompileKernel, Recover);
|
||||
HWASan = std::make_unique<HWAddressSanitizer>(M, CompileKernel, Recover,
|
||||
/*SSI=*/nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
if (shouldUseStackSafetyAnalysis(Triple(F.getParent()->getTargetTriple()),
|
||||
DisableOptimization)) {
|
||||
// We cannot call getAnalysis in doInitialization, that would cause a
|
||||
// crash as the required analyses are not initialized yet.
|
||||
HWASan->setSSI(
|
||||
&getAnalysis<StackSafetyGlobalInfoWrapperPass>().getResult());
|
||||
}
|
||||
return HWASan->sanitizeFunction(F);
|
||||
}
|
||||
|
||||
@ -361,10 +391,20 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
// This is an over-estimation of, in case we are building for an
|
||||
// architecture that doesn't allow stack tagging we will still load the
|
||||
// analysis.
|
||||
// This is so we don't need to plumb TargetTriple all the way to here.
|
||||
if (mightUseStackSafetyAnalysis(DisableOptimization))
|
||||
AU.addRequired<StackSafetyGlobalInfoWrapperPass>();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<HWAddressSanitizer> HWASan;
|
||||
bool CompileKernel;
|
||||
bool Recover;
|
||||
bool DisableOptimization;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@ -375,23 +415,32 @@ INITIALIZE_PASS_BEGIN(
|
||||
HWAddressSanitizerLegacyPass, "hwasan",
|
||||
"HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
|
||||
false)
|
||||
INITIALIZE_PASS_DEPENDENCY(StackSafetyGlobalInfoWrapperPass)
|
||||
INITIALIZE_PASS_END(
|
||||
HWAddressSanitizerLegacyPass, "hwasan",
|
||||
"HWAddressSanitizer: detect memory bugs using tagged addressing.", false,
|
||||
false)
|
||||
|
||||
FunctionPass *llvm::createHWAddressSanitizerLegacyPassPass(bool CompileKernel,
|
||||
bool Recover) {
|
||||
FunctionPass *
|
||||
llvm::createHWAddressSanitizerLegacyPassPass(bool CompileKernel, bool Recover,
|
||||
bool DisableOptimization) {
|
||||
assert(!CompileKernel || Recover);
|
||||
return new HWAddressSanitizerLegacyPass(CompileKernel, Recover);
|
||||
return new HWAddressSanitizerLegacyPass(CompileKernel, Recover,
|
||||
DisableOptimization);
|
||||
}
|
||||
|
||||
HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover)
|
||||
: CompileKernel(CompileKernel), Recover(Recover) {}
|
||||
HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover,
|
||||
bool DisableOptimization)
|
||||
: CompileKernel(CompileKernel), Recover(Recover),
|
||||
DisableOptimization(DisableOptimization) {}
|
||||
|
||||
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
|
||||
ModuleAnalysisManager &MAM) {
|
||||
HWAddressSanitizer HWASan(M, CompileKernel, Recover);
|
||||
const StackSafetyGlobalInfo *SSI = nullptr;
|
||||
if (shouldUseStackSafetyAnalysis(llvm::Triple(M.getTargetTriple()),
|
||||
DisableOptimization))
|
||||
SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
|
||||
HWAddressSanitizer HWASan(M, CompileKernel, Recover, SSI);
|
||||
bool Modified = false;
|
||||
for (Function &F : M)
|
||||
Modified |= HWASan.sanitizeFunction(F);
|
||||
@ -1245,7 +1294,9 @@ bool HWAddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
|
||||
// dynamic alloca instrumentation for them as well.
|
||||
!AI.isUsedWithInAlloca() &&
|
||||
// swifterror allocas are register promoted by ISel
|
||||
!AI.isSwiftError());
|
||||
!AI.isSwiftError()) &&
|
||||
// safe allocas are not interesting
|
||||
!(SSI && SSI->isSafe(AI));
|
||||
}
|
||||
|
||||
bool HWAddressSanitizer::sanitizeFunction(Function &F) {
|
||||
|
@ -0,0 +1,42 @@
|
||||
; RUN: opt -hwasan -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY
|
||||
; RUN: opt -hwasan -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY
|
||||
|
||||
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-linux-gnu"
|
||||
|
||||
; Check a safe alloca to ensure it does not get a tag.
|
||||
define i32 @test_load(i32* %a) sanitize_hwaddress {
|
||||
entry:
|
||||
; NOSAFETY: call {{.*}}__hwasan_generate_tag
|
||||
; SAFETY-NOT: call {{.*}}__hwasan_generate_tag
|
||||
%buf.sroa.0 = alloca i8, align 4
|
||||
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
|
||||
store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8
|
||||
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Check a non-safe alloca to ensure it gets a tag.
|
||||
define i32 @test_use(i32* %a) sanitize_hwaddress {
|
||||
entry:
|
||||
; NOSAFETY: call {{.*}}__hwasan_generate_tag
|
||||
; SAFETY: call {{.*}}__hwasan_generate_tag
|
||||
%buf.sroa.0 = alloca i8, align 4
|
||||
call void @use(i8* nonnull %buf.sroa.0)
|
||||
call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %buf.sroa.0)
|
||||
store volatile i8 0, i8* %buf.sroa.0, align 4, !tbaa !8
|
||||
call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %buf.sroa.0)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture)
|
||||
|
||||
; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn
|
||||
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture)
|
||||
|
||||
declare void @use(i8* nocapture)
|
||||
|
||||
!8 = !{!9, !9, i64 0}
|
||||
!9 = !{!"omnipotent char", !10, i64 0}
|
||||
!10 = !{!"Simple C/C++ TBAA"}
|
Loading…
Reference in New Issue
Block a user