[experimental] Add sanitizer options to LDC.

Add some of the sanitizer passes to LDC. This is not complete (linking must be
done using clang and the right `-fsanitize=` option) and may not be useful at
all.

If it proves to be usefull then a lot of other options (e.g. blacklist) must be
added.
This commit is contained in:
kai 2013-10-22 22:49:54 +02:00
parent 6fe28e1660
commit e6529cfd3d
3 changed files with 91 additions and 0 deletions

View file

@ -137,6 +137,21 @@ static int linkObjToBinaryGcc(bool sharedLib)
// create path to exe // create path to exe
CreateDirectoryOnDisk(gExePath); 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 // additional linker switches
for (unsigned i = 0; i < global.params.linkswitches->dim; i++) for (unsigned i = 0; i < global.params.linkswitches->dim; i++)
{ {

View file

@ -31,6 +31,7 @@
#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetMachine.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PassNameParser.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h"
@ -106,6 +107,17 @@ static cl::opt<bool>
stripDebug("strip-debug", stripDebug("strip-debug",
cl::desc("Strip symbolic debug information before optimization")); cl::desc("Strip symbolic debug information before optimization"));
#if LDC_LLVM_VER >= 303
cl::opt<opts::SanitizerCheck> 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() { static unsigned optLevel() {
// Use -O2 as a base for the size-optimization levels. // Use -O2 as a base for the size-optimization levels.
return optimizeLevel >= 0 ? optimizeLevel : 2; return optimizeLevel >= 0 ? optimizeLevel : 2;
@ -154,6 +166,36 @@ static void addGarbageCollect2StackPass(const PassManagerBuilder &builder, PassM
addPass(pm, createGarbageCollect2Stack()); 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 * Adds a set of optimization passes to the given module/function pass
* managers based on the given optimization and size reduction levels. * 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.DisableUnrollLoops = optLevel == 0;
/* builder.Vectorize is set in ctor from command line switch */ /* 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 (!disableLangSpecificPasses) {
if (!disableSimplifyDruntimeCalls) if (!disableSimplifyDruntimeCalls)
builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addSimplifyDRuntimeCallsPass); builder.addExtension(PassManagerBuilder::EP_LoopOptimizerEnd, addSimplifyDRuntimeCallsPass);

View file

@ -18,6 +18,17 @@
// For llvm::CodeGenOpt::Level // For llvm::CodeGenOpt::Level
#include "llvm/Support/CodeGen.h" #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<SanitizerCheck> sanitize;
}
#endif
namespace llvm { class Module; } namespace llvm { class Module; }
bool ldc_optimize_module(llvm::Module* m); bool ldc_optimize_module(llvm::Module* m);