diff --git a/driver/linker.cpp b/driver/linker.cpp index 7af669b735..850ba467ce 100644 --- a/driver/linker.cpp +++ b/driver/linker.cpp @@ -137,6 +137,21 @@ static int linkObjToBinaryGcc(bool sharedLib) // create path to exe CreateDirectoryOnDisk(gExePath); +#if LDC_LLVM_VER >= 303 + // Pass sanitizer arguments to linker. Requires clang. + if (opts::sanitize == opts::AddressSanitizer) { + args.push_back("-fsanitize=address"); + } + + if (opts::sanitize == opts::MemorySanitizer) { + args.push_back("-fsanitize=memory"); + } + + if (opts::sanitize == opts::ThreadSanitizer) { + args.push_back("-fsanitize=thread"); + } +#endif + // additional linker switches for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { diff --git a/gen/optimizer.cpp b/gen/optimizer.cpp index b0eef1d707..2c4fa313e6 100644 --- a/gen/optimizer.cpp +++ b/gen/optimizer.cpp @@ -31,6 +31,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/PassNameParser.h" +#include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -106,6 +107,17 @@ static cl::opt stripDebug("strip-debug", cl::desc("Strip symbolic debug information before optimization")); +#if LDC_LLVM_VER >= 303 +cl::opt opts::sanitize("sanitize", + cl::desc("Enable runtime instrumentation for bug detection"), + cl::init(opts::None), + cl::values( + clEnumValN(opts::AddressSanitizer, "address", "memory errors"), + clEnumValN(opts::MemorySanitizer, "memory", "memory errors"), + clEnumValN(opts::ThreadSanitizer, "thread", "race detection"), + clEnumValEnd)); +#endif + static unsigned optLevel() { // Use -O2 as a base for the size-optimization levels. return optimizeLevel >= 0 ? optimizeLevel : 2; @@ -154,6 +166,36 @@ static void addGarbageCollect2StackPass(const PassManagerBuilder &builder, PassM addPass(pm, createGarbageCollect2Stack()); } +#if LDC_LLVM_VER >= 303 +static void addAddressSanitizerPasses(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + PM.add(createAddressSanitizerFunctionPass()); + PM.add(createAddressSanitizerModulePass()); +} + +static void addMemorySanitizerPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + PM.add(createMemorySanitizerPass()); + + // MemorySanitizer inserts complex instrumentation that mostly follows + // the logic of the original code, but operates on "shadow" values. + // It can benefit from re-running some general purpose optimization passes. + if (Builder.OptLevel > 0) { + PM.add(createEarlyCSEPass()); + PM.add(createReassociatePass()); + PM.add(createLICMPass()); + PM.add(createGVNPass()); + PM.add(createInstructionCombiningPass()); + PM.add(createDeadStoreEliminationPass()); + } +} + +static void addThreadSanitizerPass(const PassManagerBuilder &Builder, + PassManagerBase &PM) { + PM.add(createThreadSanitizerPass()); +} +#endif + /** * Adds a set of optimization passes to the given module/function pass * managers based on the given optimization and size reduction levels. @@ -188,6 +230,29 @@ static void addOptimizationPasses(PassManagerBase &mpm, FunctionPassManager &fpm builder.DisableUnrollLoops = optLevel == 0; /* builder.Vectorize is set in ctor from command line switch */ +#if LDC_LLVM_VER >= 303 + if (opts::sanitize == opts::AddressSanitizer) { + builder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addAddressSanitizerPasses); + builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addAddressSanitizerPasses); + } + + if (opts::sanitize == opts::MemorySanitizer) { + builder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addMemorySanitizerPass); + builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addMemorySanitizerPass); + } + + if (opts::sanitize == opts::ThreadSanitizer) { + builder.addExtension(PassManagerBuilder::EP_OptimizerLast, + addThreadSanitizerPass); + builder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, + addThreadSanitizerPass); + } +#endif + if (!disableLangSpecificPasses) { if (!disableSimplifyDruntimeCalls) builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addSimplifyDRuntimeCallsPass); diff --git a/gen/optimizer.h b/gen/optimizer.h index b5091e9eae..784aaa5469 100644 --- a/gen/optimizer.h +++ b/gen/optimizer.h @@ -18,6 +18,17 @@ // For llvm::CodeGenOpt::Level #include "llvm/Support/CodeGen.h" +#if LDC_LLVM_VER >= 303 +#include "llvm/Support/CommandLine.h" + +namespace opts { + +enum SanitizerCheck { None, AddressSanitizer, MemorySanitizer, ThreadSanitizer }; + +extern llvm::cl::opt sanitize; +} +#endif + namespace llvm { class Module; } bool ldc_optimize_module(llvm::Module* m);