Skip to content

Commit f9e8332

Browse files
authored
Merge pull request #10330 from swiftlang/reapply-asan-fix
2 parents 9835b7e + 1f3aa41 commit f9e8332

File tree

24 files changed

+687
-363
lines changed

24 files changed

+687
-363
lines changed

clang/test/CodeGenObjC/no-sanitize.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
@interface I0 @end
44
@implementation I0
5-
// CHECK-NOT: sanitize_address
5+
// CHECK-NOT: Function Attrs: sanitize_address
66
- (void) im0: (int) a0 __attribute__((no_sanitize("address"))) {
77
int (^blockName)(void) = ^int(void) { return 0; };
88
}

llvm/include/llvm/Transforms/Instrumentation.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class Triple;
3030
class OptimizationRemarkEmitter;
3131
class Comdat;
3232
class CallBase;
33+
class Module;
34+
35+
/// Check if module has flag attached, if not add the flag.
36+
bool checkIfAlreadyInstrumented(Module &M, StringRef Flag);
3337

3438
/// Instrumentation passes often insert conditional checks into entry blocks.
3539
/// Call this function before splitting the entry block to move instructions

llvm/include/llvm/Transforms/Instrumentation/AddressSanitizerCommon.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ void getAddressSanitizerParams(const Triple &TargetTriple, int LongSize,
5858
bool IsKasan, uint64_t *ShadowBase,
5959
int *MappingScale, bool *OrShadowOffset);
6060

61+
/// Remove memory attributes that are incompatible with the instrumentation
62+
/// added by AddressSanitizer and HWAddressSanitizer.
63+
/// \p ReadsArgMem - indicates whether function arguments may be read by
64+
/// instrumentation and require removing `writeonly` attributes.
65+
void removeASanIncompatibleFnAttributes(Function &F, bool ReadsArgMem);
66+
6167
} // namespace llvm
6268

6369
#endif

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,8 @@ Expected<AddressSanitizerOptions> parseASanPassOptions(StringRef Params) {
743743

744744
if (ParamName == "kernel") {
745745
Result.CompileKernel = true;
746+
} else if (ParamName == "use-after-scope") {
747+
Result.UseAfterScope = true;
746748
} else {
747749
return make_error<StringError>(
748750
formatv("invalid AddressSanitizer pass parameter '{0}' ", ParamName)

llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,45 @@ void getAddressSanitizerParams(const Triple &TargetTriple, int LongSize,
612612
*OrShadowOffset = Mapping.OrShadowOffset;
613613
}
614614

615+
void removeASanIncompatibleFnAttributes(Function &F, bool ReadsArgMem) {
616+
// Sanitizer checks read from shadow, which invalidates memory(argmem: *).
617+
//
618+
// This is not only true for sanitized functions, because AttrInfer can
619+
// infer those attributes on libc functions, which is not true if those
620+
// are instrumented (Android) or intercepted.
621+
//
622+
// We might want to model ASan shadow memory more opaquely to get rid of
623+
// this problem altogether, by hiding the shadow memory write in an
624+
// intrinsic, essentially like in the AArch64StackTagging pass. But that's
625+
// for another day.
626+
627+
// The API is weird. `onlyReadsMemory` actually means "does not write", and
628+
// `onlyWritesMemory` actually means "does not read". So we reconstruct
629+
// "accesses memory" && "does not read" <=> "writes".
630+
bool Changed = false;
631+
if (!F.doesNotAccessMemory()) {
632+
bool WritesMemory = !F.onlyReadsMemory();
633+
bool ReadsMemory = !F.onlyWritesMemory();
634+
if ((WritesMemory && !ReadsMemory) || F.onlyAccessesArgMemory()) {
635+
F.removeFnAttr(Attribute::Memory);
636+
Changed = true;
637+
}
638+
}
639+
if (ReadsArgMem) {
640+
for (Argument &A : F.args()) {
641+
if (A.hasAttribute(Attribute::WriteOnly)) {
642+
A.removeAttr(Attribute::WriteOnly);
643+
Changed = true;
644+
}
645+
}
646+
}
647+
if (Changed) {
648+
// nobuiltin makes sure later passes don't restore assumptions about
649+
// the function.
650+
F.addFnAttr(Attribute::NoBuiltin);
651+
}
652+
}
653+
615654
ASanAccessInfo::ASanAccessInfo(int32_t Packed)
616655
: Packed(Packed),
617656
AccessSizeIndex((Packed >> kAccessSizeIndexShift) & kAccessSizeIndexMask),
@@ -1237,7 +1276,9 @@ void AddressSanitizerPass::printPipeline(
12371276
OS, MapClassName2PassName);
12381277
OS << '<';
12391278
if (Options.CompileKernel)
1240-
OS << "kernel";
1279+
OS << "kernel;";
1280+
if (Options.UseAfterScope)
1281+
OS << "use-after-scope";
12411282
OS << '>';
12421283
}
12431284

@@ -1251,6 +1292,11 @@ AddressSanitizerPass::AddressSanitizerPass(
12511292

12521293
PreservedAnalyses AddressSanitizerPass::run(Module &M,
12531294
ModuleAnalysisManager &MAM) {
1295+
// Return early if nosanitize_address module flag is present for the module.
1296+
// This implies that asan pass has already run before.
1297+
if (checkIfAlreadyInstrumented(M, "nosanitize_address"))
1298+
return PreservedAnalyses::all();
1299+
12541300
ModuleAddressSanitizer ModuleSanitizer(
12551301
M, Options.InsertVersionCheck, Options.CompileKernel, Options.Recover,
12561302
UseGlobalGC, UseOdrIndicator, DestructorKind, ConstructorKind);
@@ -2730,6 +2776,9 @@ int ModuleAddressSanitizer::GetAsanVersion(const Module &M) const {
27302776
bool ModuleAddressSanitizer::instrumentModule(Module &M) {
27312777
initializeCallbacks(M);
27322778

2779+
for (Function &F : M)
2780+
removeASanIncompatibleFnAttributes(F, /*ReadsArgMem=*/false);
2781+
27332782
// Create a module constructor. A destructor is created lazily because not all
27342783
// platforms, and not all modules need it.
27352784
if (ConstructorKind == AsanCtorKind::Global) {

llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,9 @@ void DFSanVisitor::visitPHINode(PHINode &PN) {
34733473

34743474
PreservedAnalyses DataFlowSanitizerPass::run(Module &M,
34753475
ModuleAnalysisManager &AM) {
3476+
// Return early if nosanitize_dataflow module flag is present for the module.
3477+
if (checkIfAlreadyInstrumented(M, "nosanitize_dataflow"))
3478+
return PreservedAnalyses::all();
34763479
auto GetTLI = [&](Function &F) -> TargetLibraryInfo & {
34773480
auto &FAM =
34783481
AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();

llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "llvm/Support/RandomNumberGenerator.h"
5858
#include "llvm/Support/raw_ostream.h"
5959
#include "llvm/TargetParser/Triple.h"
60+
#include "llvm/Transforms/Instrumentation.h"
6061
#include "llvm/Transforms/Instrumentation/AddressSanitizerCommon.h"
6162
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
6263
#include "llvm/Transforms/Utils/Local.h"
@@ -455,6 +456,9 @@ class HWAddressSanitizer {
455456

456457
PreservedAnalyses HWAddressSanitizerPass::run(Module &M,
457458
ModuleAnalysisManager &MAM) {
459+
// Return early if nosanitize_hwaddress module flag is present for the module.
460+
if (checkIfAlreadyInstrumented(M, "nosanitize_hwaddress"))
461+
return PreservedAnalyses::all();
458462
const StackSafetyGlobalInfo *SSI = nullptr;
459463
auto TargetTriple = llvm::Triple(M.getTargetTriple());
460464
if (shouldUseStackSafetyAnalysis(TargetTriple, Options.DisableOptimization))
@@ -594,6 +598,11 @@ void HWAddressSanitizer::initializeModule() {
594598
LLVM_DEBUG(dbgs() << "Init " << M.getName() << "\n");
595599
TargetTriple = Triple(M.getTargetTriple());
596600

601+
// HWASan may do short granule checks on function arguments read from the
602+
// argument memory (last byte of the granule), which invalidates writeonly.
603+
for (Function &F : M.functions())
604+
removeASanIncompatibleFnAttributes(F, /*ReadsArgMem=*/true);
605+
597606
// x86_64 currently has two modes:
598607
// - Intel LAM (default)
599608
// - pointer aliasing (heap only)
@@ -1613,14 +1622,6 @@ void HWAddressSanitizer::sanitizeFunction(Function &F,
16131622

16141623
assert(!ShadowBase);
16151624

1616-
// Remove memory attributes that are about to become invalid.
1617-
// HWASan checks read from shadow, which invalidates memory(argmem: *)
1618-
// Short granule checks on function arguments read from the argument memory
1619-
// (last byte of the granule), which invalidates writeonly.
1620-
F.removeFnAttr(llvm::Attribute::Memory);
1621-
for (auto &A : F.args())
1622-
A.removeAttr(llvm::Attribute::WriteOnly);
1623-
16241625
BasicBlock::iterator InsertPt = F.getEntryBlock().begin();
16251626
IRBuilder<> EntryIRB(&F.getEntryBlock(), InsertPt);
16261627
emitPrologue(EntryIRB,

llvm/lib/Transforms/Instrumentation/Instrumentation.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,47 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm/Transforms/Instrumentation.h"
15+
#include "llvm/IR/DiagnosticInfo.h"
16+
#include "llvm/IR/DiagnosticPrinter.h"
1517
#include "llvm/IR/IntrinsicInst.h"
1618
#include "llvm/IR/Module.h"
1719
#include "llvm/TargetParser/Triple.h"
1820

1921
using namespace llvm;
2022

23+
static cl::opt<bool> ClIgnoreRedundantInstrumentation(
24+
"ignore-redundant-instrumentation",
25+
cl::desc("Ignore redundant instrumentation"), cl::Hidden, cl::init(false));
26+
27+
namespace {
28+
/// Diagnostic information for IR instrumentation reporting.
29+
class DiagnosticInfoInstrumentation : public DiagnosticInfo {
30+
const Twine &Msg;
31+
32+
public:
33+
DiagnosticInfoInstrumentation(const Twine &DiagMsg,
34+
DiagnosticSeverity Severity = DS_Warning)
35+
: DiagnosticInfo(DK_Linker, Severity), Msg(DiagMsg) {}
36+
void print(DiagnosticPrinter &DP) const override { DP << Msg; }
37+
};
38+
} // namespace
39+
40+
/// Check if module has flag attached, if not add the flag.
41+
bool llvm::checkIfAlreadyInstrumented(Module &M, StringRef Flag) {
42+
if (!M.getModuleFlag(Flag)) {
43+
M.addModuleFlag(Module::ModFlagBehavior::Override, Flag, 1);
44+
return false;
45+
}
46+
if (ClIgnoreRedundantInstrumentation)
47+
return true;
48+
std::string diagInfo =
49+
"Redundant instrumentation detected, with module flag: " +
50+
std::string(Flag);
51+
M.getContext().diagnose(
52+
DiagnosticInfoInstrumentation(diagInfo, DiagnosticSeverity::DS_Warning));
53+
return true;
54+
}
55+
2156
/// Moves I before IP. Returns new insert point.
2257
static BasicBlock::iterator moveBeforeInsertPoint(BasicBlock::iterator I, BasicBlock::iterator IP) {
2358
// If I is IP, move the insert point down.

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@
198198
#include "llvm/Support/MathExtras.h"
199199
#include "llvm/Support/raw_ostream.h"
200200
#include "llvm/TargetParser/Triple.h"
201+
#include "llvm/Transforms/Instrumentation.h"
201202
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
202203
#include "llvm/Transforms/Utils/Local.h"
203204
#include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -706,6 +707,9 @@ MemorySanitizerOptions::MemorySanitizerOptions(int TO, bool R, bool K,
706707

707708
PreservedAnalyses MemorySanitizerPass::run(Module &M,
708709
ModuleAnalysisManager &AM) {
710+
// Return early if nosanitize_memory module flag is present for the module.
711+
if (checkIfAlreadyInstrumented(M, "nosanitize_memory"))
712+
return PreservedAnalyses::all();
709713
bool Modified = false;
710714
if (!Options.Kernel) {
711715
insertModuleCtor(M);

llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ PreservedAnalyses ThreadSanitizerPass::run(Function &F,
191191

192192
PreservedAnalyses ModuleThreadSanitizerPass::run(Module &M,
193193
ModuleAnalysisManager &MAM) {
194+
// Return early if nosanitize_thread module flag is present for the module.
195+
if (checkIfAlreadyInstrumented(M, "nosanitize_thread"))
196+
return PreservedAnalyses::all();
194197
insertModuleCtor(M);
195198
return PreservedAnalyses::none();
196199
}

0 commit comments

Comments
 (0)