@@ -316,6 +316,7 @@ class HWAddressSanitizer {
316
316
FunctionAnalysisManager &FAM) const ;
317
317
void initializeModule ();
318
318
void createHwasanCtorComdat ();
319
+ void removeFnAttributes (Function *F);
319
320
320
321
void initializeCallbacks (Module &M);
321
322
@@ -591,47 +592,55 @@ void HWAddressSanitizer::createHwasanCtorComdat() {
591
592
appendToCompilerUsed (M, Dummy);
592
593
}
593
594
595
+ void HWAddressSanitizer::removeFnAttributes (Function *F) {
596
+ // Remove memory attributes that are invalid with HWASan.
597
+ // HWASan checks read from shadow, which invalidates memory(argmem: *)
598
+ // Short granule checks on function arguments read from the argument memory
599
+ // (last byte of the granule), which invalidates writeonly.
600
+ //
601
+ // This is not only true for sanitized functions, because AttrInfer can
602
+ // infer those attributes on libc functions, which is not true if those
603
+ // are instrumented (Android) or intercepted.
604
+ //
605
+ // We might want to model HWASan shadow memory more opaquely to get rid of
606
+ // this problem altogether, by hiding the shadow memory write in an
607
+ // intrinsic, essentially like in the AArch64StackTagging pass. But that's
608
+ // for another day.
609
+
610
+ // The API is weird. `onlyReadsMemory` actually means "does not write", and
611
+ // `onlyWritesMemory` actually means "does not read". So we reconstruct
612
+ // "accesses memory" && "does not read" <=> "writes".
613
+ bool Changed = false ;
614
+ if (!F->doesNotAccessMemory ()) {
615
+ bool WritesMemory = !F->onlyReadsMemory ();
616
+ bool ReadsMemory = !F->onlyWritesMemory ();
617
+ if ((WritesMemory && !ReadsMemory) || F->onlyAccessesArgMemory ()) {
618
+ F->removeFnAttr (Attribute::Memory);
619
+ Changed = true ;
620
+ }
621
+ }
622
+ for (Argument &A : F->args ()) {
623
+ if (A.hasAttribute (Attribute::WriteOnly)) {
624
+ A.removeAttr (Attribute::WriteOnly);
625
+ Changed = true ;
626
+ }
627
+ }
628
+ if (Changed) {
629
+ // nobuiltin makes sure later passes don't restore assumptions about
630
+ // the function.
631
+ F->addFnAttr (Attribute::NoBuiltin);
632
+ }
633
+ }
634
+
594
635
// / Module-level initialization.
595
636
// /
596
637
// / inserts a call to __hwasan_init to the module's constructor list.
597
638
void HWAddressSanitizer::initializeModule () {
598
639
LLVM_DEBUG (dbgs () << " Init " << M.getName () << " \n " );
599
640
TargetTriple = Triple (M.getTargetTriple ());
600
641
601
- for (auto &F : M.functions ()) {
602
- // Remove memory attributes that are invalid with HWASan.
603
- // HWASan checks read from shadow, which invalidates memory(argmem: *)
604
- // Short granule checks on function arguments read from the argument memory
605
- // (last byte of the granule), which invalidates writeonly.
606
- //
607
- // This is not only true for sanitized functions, because AttrInfer can
608
- // infer those attributes on libc functions, which is not true if those
609
- // are instrumented (Android) or intercepted.
610
-
611
- // The API is weird. `onlyReadsMemory` actually means "does not write", and
612
- // `onlyWritesMemory` actually means "does not read". So we reconstruct
613
- // "accesses memory" && "does not read" <=> "writes".
614
- bool Changed = false ;
615
- if (!F.doesNotAccessMemory ()) {
616
- bool WritesMemory = !F.onlyReadsMemory ();
617
- bool ReadsMemory = !F.onlyWritesMemory ();
618
- if ((WritesMemory && !ReadsMemory) || F.onlyAccessesArgMemory ()) {
619
- F.removeFnAttr (Attribute::Memory);
620
- Changed = true ;
621
- }
622
- }
623
- for (Argument &A : F.args ()) {
624
- if (A.hasAttribute (Attribute::WriteOnly)) {
625
- Changed = true ;
626
- A.removeAttr (Attribute::WriteOnly);
627
- }
628
- }
629
- if (Changed) {
630
- // nobuiltin makes sure later passes don't restore assumptions about
631
- // the function.
632
- F.addFnAttr (Attribute::NoBuiltin);
633
- }
634
- }
642
+ for (Function &F : M.functions ())
643
+ removeFnAttributes (&F);
635
644
636
645
// x86_64 currently has two modes:
637
646
// - Intel LAM (default)
0 commit comments