Skip to content

[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

Merged
merged 5 commits into from
Sep 28, 2023

Conversation

thurstond
Copy link
Contributor

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

…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
@llvmbot
Copy link
Member

llvmbot commented Sep 20, 2023

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-compiler-rt-sanitizer

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/66935.diff

1 Files Affected:

  • (modified) llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp (+9-1)
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();
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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>();
Copy link
Contributor

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.

Copy link
Contributor

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)

Copy link
Contributor Author

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
Copy link
Contributor

@fmayer fmayer left a 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);
Copy link
Contributor

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.

Copy link
Contributor Author

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) {
Copy link
Contributor

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?

Copy link
Contributor Author

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
@thurstond thurstond requested a review from fhahn September 27, 2023 22:19
@aeubanks
Copy link
Contributor

title needs to be updated

Copy link
Contributor

@fhahn fhahn left a 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!

@thurstond thurstond changed the title [hwasan] Invalidate DominatorTreeAnalysis after each function is sanitized [hwasan] Update (Post-)DominatorTreeAnalysis and LoopAnalysis incrementally Sep 28, 2023
@thurstond
Copy link
Contributor Author

title needs to be updated

@aeubanks Done, thanks for the heads up!

@thurstond
Copy link
Contributor Author

Thanks for the latest updates, LGTM!

@fhahn Thanks for all the helpful guidance!

@thurstond thurstond merged commit b3b6ede into llvm:main Sep 28, 2023
legrosbuffle pushed a commit to legrosbuffle/llvm-project that referenced this pull request Sep 29, 2023
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants