[NewPM] Make some sanitizer passes parameterized in the PassRegistry

Refactored implementation of AddressSanitizerPass and
HWAddressSanitizerPass to use pass options similar to passes like
MemorySanitizerPass. This makes sure that there is a single mapping
from class name to pass name (needed by D108298), and options like
-debug-only and -print-after makes a bit more sense when (despite
that it is the unparameterized pass name that should be used in those
options).

A result of the above is that some pass names are removed in favor
of the parameterized versions:
- "khwasan" is now "hwasan<kernel;recover>"
- "kasan" is now "asan<kernel>"
- "kmsan" is now "msan<kernel>"

Differential Revision: https://reviews.llvm.org/D105007
This commit is contained in:
Bjorn Pettersson 2021-06-28 11:16:40 +02:00
parent 23b16d2453
commit 36d5138619
8 changed files with 117 additions and 40 deletions

View File

@ -1161,7 +1161,7 @@ static void addSanitizers(const Triple &TargetTriple,
CompileKernel, Recover, ModuleUseAfterScope, UseOdrIndicator,
DestructorKind));
MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass(
CompileKernel, Recover, UseAfterScope, UseAfterReturn)));
{CompileKernel, Recover, UseAfterScope, UseAfterReturn})));
}
};
ASanPass(SanitizerKind::Address, false);
@ -1171,8 +1171,8 @@ static void addSanitizers(const Triple &TargetTriple,
if (LangOpts.Sanitize.has(Mask)) {
bool Recover = CodeGenOpts.SanitizeRecover.has(Mask);
MPM.addPass(HWAddressSanitizerPass(
CompileKernel, Recover,
/*DisableOptimization=*/CodeGenOpts.OptimizationLevel == 0));
{CompileKernel, Recover,
/*DisableOptimization=*/CodeGenOpts.OptimizationLevel == 0}));
}
};
HWASanPass(SanitizerKind::HWAddress, false);

View File

@ -89,6 +89,20 @@ private:
static AnalysisKey Key;
};
struct AddressSanitizerOptions {
AddressSanitizerOptions()
: AddressSanitizerOptions(false, false, false,
AsanDetectStackUseAfterReturnMode::Runtime){};
AddressSanitizerOptions(bool CompileKernel, bool Recover, bool UseAfterScope,
AsanDetectStackUseAfterReturnMode UseAfterReturn)
: CompileKernel(CompileKernel), Recover(Recover),
UseAfterScope(UseAfterScope), UseAfterReturn(UseAfterReturn){};
bool CompileKernel;
bool Recover;
bool UseAfterScope;
AsanDetectStackUseAfterReturnMode UseAfterReturn;
};
/// Public interface to the address sanitizer pass for instrumenting code to
/// check for various memory errors at runtime.
///
@ -98,19 +112,13 @@ private:
/// surrounding requested memory to be checked for invalid accesses.
class AddressSanitizerPass : public PassInfoMixin<AddressSanitizerPass> {
public:
explicit AddressSanitizerPass(
bool CompileKernel = false, bool Recover = false,
bool UseAfterScope = false,
AsanDetectStackUseAfterReturnMode UseAfterReturn =
AsanDetectStackUseAfterReturnMode::Runtime);
explicit AddressSanitizerPass(AddressSanitizerOptions Options)
: Options(Options){};
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
static bool isRequired() { return true; }
private:
bool CompileKernel;
bool Recover;
bool UseAfterScope;
AsanDetectStackUseAfterReturnMode UseAfterReturn;
AddressSanitizerOptions Options;
};
/// Public interface to the address sanitizer module pass for instrumenting code

View File

@ -18,21 +18,30 @@
namespace llvm {
struct HWAddressSanitizerOptions {
HWAddressSanitizerOptions()
: HWAddressSanitizerOptions(false, false, false){};
HWAddressSanitizerOptions(bool CompileKernel, bool Recover,
bool DisableOptimization)
: CompileKernel(CompileKernel), Recover(Recover),
DisableOptimization(DisableOptimization){};
bool CompileKernel;
bool Recover;
bool DisableOptimization;
};
/// This is a public interface to the hardware address sanitizer pass for
/// instrumenting code to check for various memory errors at runtime, similar to
/// AddressSanitizer but based on partial hardware assistance.
class HWAddressSanitizerPass : public PassInfoMixin<HWAddressSanitizerPass> {
public:
explicit HWAddressSanitizerPass(bool CompileKernel = false,
bool Recover = false,
bool DisableOptimization = false);
explicit HWAddressSanitizerPass(HWAddressSanitizerOptions Options)
: Options(Options){};
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
static bool isRequired() { return true; }
private:
bool CompileKernel;
bool Recover;
bool DisableOptimization;
HWAddressSanitizerOptions Options;
};
FunctionPass *

View File

@ -453,6 +453,8 @@ PassBuilder::PassBuilder(TargetMachine *TM, PipelineTuningOptions PTO,
if (PIC && shouldPopulateClassToPassNames()) {
#define MODULE_PASS(NAME, CREATE_PASS) \
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
PIC->addClassToPassName(CLASS, NAME);
#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
PIC->addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
#define FUNCTION_PASS(NAME, CREATE_PASS) \
@ -2137,6 +2139,44 @@ Expected<LoopUnrollOptions> parseLoopUnrollOptions(StringRef Params) {
return UnrollOpts;
}
Expected<AddressSanitizerOptions> parseASanPassOptions(StringRef Params) {
AddressSanitizerOptions Result;
while (!Params.empty()) {
StringRef ParamName;
std::tie(ParamName, Params) = Params.split(';');
if (ParamName == "kernel") {
Result.CompileKernel = true;
} else {
return make_error<StringError>(
formatv("invalid AddressSanitizer pass parameter '{0}' ", ParamName)
.str(),
inconvertibleErrorCode());
}
}
return Result;
}
Expected<HWAddressSanitizerOptions> parseHWASanPassOptions(StringRef Params) {
HWAddressSanitizerOptions Result;
while (!Params.empty()) {
StringRef ParamName;
std::tie(ParamName, Params) = Params.split(';');
if (ParamName == "recover") {
Result.Recover = true;
} else if (ParamName == "kernel") {
Result.CompileKernel = true;
} else {
return make_error<StringError>(
formatv("invalid HWAddressSanitizer pass parameter '{0}' ", ParamName)
.str(),
inconvertibleErrorCode());
}
}
return Result;
}
Expected<MemorySanitizerOptions> parseMSanPassOptions(StringRef Params) {
MemorySanitizerOptions Result;
while (!Params.empty()) {
@ -2356,6 +2396,9 @@ static bool isModulePassName(StringRef Name, CallbacksT &Callbacks) {
#define MODULE_PASS(NAME, CREATE_PASS) \
if (Name == NAME) \
return true;
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
if (checkParametrizedPassName(Name, NAME)) \
return true;
#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
return true;
@ -2600,6 +2643,14 @@ Error PassBuilder::parseModulePass(ModulePassManager &MPM,
MPM.addPass(CREATE_PASS); \
return Error::success(); \
}
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
if (checkParametrizedPassName(Name, NAME)) { \
auto Params = parsePassParameters(PARSER, Name, NAME); \
if (!Params) \
return Params.takeError(); \
MPM.addPass(CREATE_PASS(Params.get())); \
return Error::success(); \
}
#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
if (Name == "require<" NAME ">") { \
MPM.addPass( \
@ -3176,6 +3227,11 @@ void PassBuilder::printPassNames(raw_ostream &OS) {
#define MODULE_PASS(NAME, CREATE_PASS) printPassName(NAME, OS);
#include "PassRegistry.def"
OS << "Module passes with params:\n";
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS) \
printPassName(NAME, PARAMS, OS);
#include "PassRegistry.def"
OS << "Module analyses:\n";
#define MODULE_ANALYSIS(NAME, CREATE_PASS) printPassName(NAME, OS);
#include "PassRegistry.def"

View File

@ -60,8 +60,6 @@ MODULE_PASS("globaldce", GlobalDCEPass())
MODULE_PASS("globalopt", GlobalOptPass())
MODULE_PASS("globalsplit", GlobalSplitPass())
MODULE_PASS("hotcoldsplit", HotColdSplittingPass())
MODULE_PASS("hwasan", HWAddressSanitizerPass(false, false))
MODULE_PASS("khwasan", HWAddressSanitizerPass(true, true))
MODULE_PASS("inferattrs", InferFunctionAttrsPass())
MODULE_PASS("inliner-wrapper", ModuleInlinerWrapperPass())
MODULE_PASS("inliner-wrapper-no-mandatory-first", ModuleInlinerWrapperPass(
@ -123,6 +121,18 @@ MODULE_PASS("poison-checking", PoisonCheckingPass())
MODULE_PASS("pseudo-probe-update", PseudoProbeUpdatePass())
#undef MODULE_PASS
#ifndef MODULE_PASS_WITH_PARAMS
#define MODULE_PASS_WITH_PARAMS(NAME, CLASS, CREATE_PASS, PARSER, PARAMS)
#endif
MODULE_PASS_WITH_PARAMS("hwasan",
"HWAddressSanitizerPass",
[](HWAddressSanitizerOptions Opts) {
return HWAddressSanitizerPass(Opts);
},
parseHWASanPassOptions,
"kernel;recover")
#undef MODULE_PASS_WITH_PARAMS
#ifndef CGSCC_ANALYSIS
#define CGSCC_ANALYSIS(NAME, CREATE_PASS)
#endif
@ -322,10 +332,7 @@ FUNCTION_PASS("verify<scalar-evolution>", ScalarEvolutionVerifierPass())
FUNCTION_PASS("view-cfg", CFGViewerPass())
FUNCTION_PASS("view-cfg-only", CFGOnlyViewerPass())
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
FUNCTION_PASS("asan", AddressSanitizerPass(false, false, false))
FUNCTION_PASS("kasan", AddressSanitizerPass(true, false, false))
FUNCTION_PASS("msan", MemorySanitizerPass({}))
FUNCTION_PASS("kmsan", MemorySanitizerPass({0, false, /*Kernel=*/true}))
FUNCTION_PASS("tsan", ThreadSanitizerPass())
FUNCTION_PASS("memprof", MemProfilerPass())
#undef FUNCTION_PASS
@ -345,6 +352,13 @@ FUNCTION_PASS_WITH_PARAMS("loop-unroll",
"no-profile-peeling;profile-peeling;"
"no-runtime;runtime;"
"no-upperbound;upperbound")
FUNCTION_PASS_WITH_PARAMS("asan",
"AddressSanitizerPass",
[](AddressSanitizerOptions Opts) {
return AddressSanitizerPass(Opts);
},
parseASanPassOptions,
"kernel")
FUNCTION_PASS_WITH_PARAMS("msan",
"MemorySanitizerPass",
[](MemorySanitizerOptions Opts) {

View File

@ -1212,20 +1212,14 @@ GlobalsMetadata ASanGlobalsMetadataAnalysis::run(Module &M,
return GlobalsMetadata(M);
}
AddressSanitizerPass::AddressSanitizerPass(
bool CompileKernel, bool Recover, bool UseAfterScope,
AsanDetectStackUseAfterReturnMode UseAfterReturn)
: CompileKernel(CompileKernel), Recover(Recover),
UseAfterScope(UseAfterScope), UseAfterReturn(UseAfterReturn) {}
PreservedAnalyses AddressSanitizerPass::run(Function &F,
AnalysisManager<Function> &AM) {
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
Module &M = *F.getParent();
if (auto *R = MAMProxy.getCachedResult<ASanGlobalsMetadataAnalysis>(M)) {
const TargetLibraryInfo *TLI = &AM.getResult<TargetLibraryAnalysis>(F);
AddressSanitizer Sanitizer(M, R, CompileKernel, Recover, UseAfterScope,
UseAfterReturn);
AddressSanitizer Sanitizer(M, R, Options.CompileKernel, Options.Recover,
Options.UseAfterScope, Options.UseAfterReturn);
if (Sanitizer.instrumentFunction(F, TLI))
return PreservedAnalyses::none();
return PreservedAnalyses::all();

View File

@ -471,19 +471,14 @@ llvm::createHWAddressSanitizerLegacyPassPass(bool CompileKernel, bool Recover,
DisableOptimization);
}
HWAddressSanitizerPass::HWAddressSanitizerPass(bool CompileKernel, bool Recover,
bool DisableOptimization)
: CompileKernel(CompileKernel), Recover(Recover),
DisableOptimization(DisableOptimization) {}
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
ModuleAnalysisManager &MAM) {
const StackSafetyGlobalInfo *SSI = nullptr;
auto TargetTriple = llvm::Triple(M.getTargetTriple());
if (shouldUseStackSafetyAnalysis(TargetTriple, DisableOptimization))
if (shouldUseStackSafetyAnalysis(TargetTriple, Options.DisableOptimization))
SSI = &MAM.getResult<StackSafetyGlobalAnalysis>(M);
HWAddressSanitizer HWASan(M, CompileKernel, Recover, SSI);
HWAddressSanitizer HWASan(M, Options.CompileKernel, Options.Recover, SSI);
bool Modified = false;
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
for (Function &F : M) {

View File

@ -339,18 +339,19 @@ bool llvm::runPassPipeline(StringRef Arg0, Module &M, TargetMachine *TM,
PB.registerPipelineParsingCallback(
[](StringRef Name, ModulePassManager &MPM,
ArrayRef<PassBuilder::PipelineElement>) {
AddressSanitizerOptions Opts;
if (Name == "asan-pipeline") {
MPM.addPass(
RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
MPM.addPass(
createModuleToFunctionPassAdaptor(AddressSanitizerPass()));
createModuleToFunctionPassAdaptor(AddressSanitizerPass(Opts)));
MPM.addPass(ModuleAddressSanitizerPass());
return true;
} else if (Name == "asan-function-pipeline") {
MPM.addPass(
RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
MPM.addPass(
createModuleToFunctionPassAdaptor(AddressSanitizerPass()));
createModuleToFunctionPassAdaptor(AddressSanitizerPass(Opts)));
return true;
}
return false;