-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[hwasan] Update (Post-)DominatorTreeAnalysis and LoopAnalysis incrementally #66935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…tized HWAddressSanitizerPass::run sanitizes functions one by one. The sanitization of each function - which may split blocks via insertShadowTagCheck - may result in some cached analyses are invalid. This matters because sanitizeFunction(F', FAM) may indirectly call the global stack safety analysis, hence we need to make sure the analyses of F are up to date. Bug report: llvm#66934
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-compiler-rt-sanitizer ChangesHWAddressSanitizerPass::run sanitizes functions one by one. The sanitization of each function - which may split blocks via insertShadowTagCheck - may result in some cached analyses are invalid. This matters because sanitizeFunction(F', FAM) may indirectly call the global stack safety analysis, hence we need to make sure the analyses of F are up to date. Bug report: #66934 Full diff: https://github.com/llvm/llvm-project/pull/66935.diff 1 Files Affected:
diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
index 29770ece9c61eb2..1dc550ba8b54ea6 100644
--- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
@@ -430,8 +430,16 @@ PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
HWAddressSanitizer HWASan(M, Options.CompileKernel, Options.Recover, SSI);
auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
- for (Function &F : M)
+ for (Function &F : M) {
HWASan.sanitizeFunction(F, FAM);
+ // After sanitizing F - which may split blocks via insertShadowTagCheck -
+ // some cached analyses are invalid. This matters because
+ // sanitizeFunction(F', FAM) may indirectly call the global stack safety
+ // analysis, hence we need to make sure the analyses of F are up to date.
+ PreservedAnalyses PA = PreservedAnalyses::all();
+ PA.abandon<DominatorTreeAnalysis>();
+ FAM.invalidate(F, PA);
+ }
PreservedAnalyses PA = PreservedAnalyses::none();
// GlobalsAA is considered stateless and does not get invalidated unless
|
// some cached analyses are invalid. This matters because | ||
// sanitizeFunction(F', FAM) may indirectly call the global stack safety | ||
// analysis, hence we need to make sure the analyses of F are up to date. | ||
PreservedAnalyses PA = PreservedAnalyses::all(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing, in particular because below it marks all analysis as not preserved. Should we invalidate all analysis here?
Also, the dominator tree should be very easy to preserve, to save some compile-time: SplitBlockAndInsertIfThen
takes an optional DomTreeUpdater object to update the dominator tree.
I didn't take a look at how the pass uses the dominator tree, but if the dominator tree isn't updated after making changes to the CFG and is later used again in the same function, then it may use an out-of-date dominator tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing, in particular because below it marks all analysis as not preserved. Should we invalidate all analysis here?
ASan, MSan, DFSan and HWASan all share the same "invalidate all the analyses, including GlobalsAA, at the end of the pass" boilerplate code, so perhaps it's not strictly necessary for HWASan.
But even if all the analyses are stale at the end of the HWASan pass, they don't necessarily need to be eagerly invalidated after each function is sanitized, as long as the analysis is not used by the rest of the HWASan pass. The stack safety global analysis is a special case because, by definition, it looks at every function.
Also, the dominator tree should be very easy to preserve, to save some compile-time:
SplitBlockAndInsertIfThen
takes an optional DomTreeUpdater object to update the dominator tree.
That's a good idea, thanks! I'll update the pull request shortly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P.S. I'm honored to have two Florians review my patch 😀
This patch incrementally updates the DominatorTreeAnalysis and LoopAnalysis whenever SplitBlockAndInsertIfThen is called, which fixes the following issue: Suppose we have two functions, F and G. HWAddressSanitizerPass::run will first sanitize F, which potentially makes the analyses of F out of date. When G is then sanitized, it may call the global stack safety analysis, which can crash if the analysis of F is stale. Additionally, since the DominatorTreeAnalysis and LoopAnalysis are now incrementally updated, they do not need to be abandoned at the end of the pass. Bug report: llvm#66934
DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F); | ||
PostDominatorTree &PDT = FAM.getResult<PostDominatorTreeAnalysis>(F); | ||
DomTreeUpdater DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy); | ||
LoopInfo &LI = FAM.getResult<LoopAnalysis>(F); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could pull the definitions for DT PDT and LI out of the if in 1538 then we need not repeat them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks!
This patch incrementally updates the DominatorTreeAnalysis and LoopAnalysis whenever SplitBlockAndInsertIfThen is called, which fixes the following issue: Suppose we have two functions, F and G. HWAddressSanitizerPass::run will first sanitize F, which potentially makes the analyses of F out of date. When G is then sanitized, it may call the global stack safety analysis, which can crash if the analysis of F is stale. Additionally, since the DominatorTreeAnalysis and LoopAnalysis are now incrementally updated, they do not need to be abandoned at the end of the pass. Bug report: llvm#66934
// DominatorTreeAnalysis and LoopAnalysis are incrementally updated | ||
// throughout this pass whenever SplitBlockAndInsertIfThen is called. | ||
PA.preserve<DominatorTreeAnalysis>(); | ||
PA.preserve<LoopAnalysis>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add PostDominatorTreeAnalysis here too? Seems like DomTreeUpdater also takes care of that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(And if not, please add a comment in the code on why not, because I think that's a natural question)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, added.
…ntally This patch incrementally updates the DominatorTreeAnalysis, PostDominatorTreeAnalysis and LoopAnalysis whenever SplitBlockAndInsertIfThen is called, which fixes the following issue: Suppose we have two functions, F and G. HWAddressSanitizerPass::run will first sanitize F, which potentially makes the analyses of F out of date. When G is then sanitized, it may call the global stack safety analysis, which can crash if the analysis of F is stale. Additionally, since the DominatorTreeAnalysis, PostDominatorTreeAnalysis and LoopAnalysis are now incrementally updated, they do not need to be abandoned at the end of the pass. Bug report: llvm#66934
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I give this CL 1 / 2 Florians.
@@ -1520,10 +1537,10 @@ void HWAddressSanitizer::sanitizeFunction(Function &F, | |||
Mapping.WithFrameRecord && | |||
!SInfo.AllocasToInstrument.empty()); | |||
|
|||
DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This now may request the DT/LI/PDT in cases where it wasn't before, which should probably avoided. In cases they are only needed for updating them/preserving them, you can use FAM.getCachedResult
, which won't cause the DT to be computed if it isn't already cached.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks for the suggestion!
HWAddressSanitizer::insertShadowTagCheck(Value *Ptr, | ||
Instruction *InsertBefore) { | ||
HWAddressSanitizer::insertShadowTagCheck(Value *Ptr, Instruction *InsertBefore, | ||
DomTreeUpdater *DTU, LoopInfo *LI) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Across all those interfaces, both DTU
and LI
will always be non-null. Better to pass as reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, done!
…ntally This patch incrementally updates the DominatorTreeAnalysis, PostDominatorTreeAnalysis and LoopAnalysis whenever SplitBlockAndInsertIfThen is called, which fixes the following issue: Suppose we have two functions, F and G. HWAddressSanitizerPass::run will first sanitize F, which potentially makes the analyses of F out of date. When G is then sanitized, it may call the global stack safety analysis, which can crash if the analysis of F is stale. Additionally, since the DominatorTreeAnalysis, PostDominatorTreeAnalysis and LoopAnalysis are now incrementally updated, they do not need to be abandoned at the end of the pass. Bug report: llvm#66934
title needs to be updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the latest updates, LGTM!
@aeubanks Done, thanks for the heads up! |
@fhahn Thanks for all the helpful guidance! |
…ntally (llvm#66935) HWAddressSanitizerPass::run sanitizes functions one by one. The sanitization of each function - which may split blocks via insertShadowTagCheck - may result in some cached analyses are invalid. This matters because sanitizeFunction(F', FAM) may indirectly call the global stack safety analysis, hence we need to make sure the analyses of F are up to date. Bug report: llvm#66934
HWAddressSanitizerPass::run sanitizes functions one by one. The sanitization of each function - which may split blocks via insertShadowTagCheck - may result in some cached analyses are invalid. This matters because sanitizeFunction(F', FAM) may indirectly call the global stack safety analysis, hence we need to make sure the analyses of F are up to date.
Bug report: #66934