@@ -316,6 +316,7 @@ class HWAddressSanitizer {
316316 FunctionAnalysisManager &FAM) const ;
317317 void initializeModule ();
318318 void createHwasanCtorComdat ();
319+ void removeFnAttributes (Function *F);
319320
320321 void initializeCallbacks (Module &M);
321322
@@ -591,47 +592,55 @@ void HWAddressSanitizer::createHwasanCtorComdat() {
591592 appendToCompilerUsed (M, Dummy);
592593}
593594
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+
594635// / Module-level initialization.
595636// /
596637// / inserts a call to __hwasan_init to the module's constructor list.
597638void HWAddressSanitizer::initializeModule () {
598639 LLVM_DEBUG (dbgs () << " Init " << M.getName () << " \n " );
599640 TargetTriple = Triple (M.getTargetTriple ());
600641
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);
635644
636645 // x86_64 currently has two modes:
637646 // - Intel LAM (default)
0 commit comments