From 25601fbac722b9af61ebaf69014e4b73517aaf94 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 24 May 2018 03:23:50 +0200 Subject: Add sanitize build/test option, currently ignored if gcc is not used --- backend/ninja/Ninja.cpp | 18 +++++++++++++--- include/Conf.hpp | 14 ++++++++++++- sibs_multilib.kdev4 | 4 ++++ src/CmakeModule.cpp | 8 +++++++ src/main.cpp | 56 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 sibs_multilib.kdev4 diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp index 35922ee..c72c99f 100644 --- a/backend/ninja/Ninja.cpp +++ b/backend/ninja/Ninja.cpp @@ -722,12 +722,17 @@ namespace backend switch (config.getOptimizationLevel()) { case OPT_LEV_DEBUG: - result += " -g3 -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables -fsanitize=address -fsanitize=undefined "; + result += " -g3 -D_FORTIFY_SOURCE=2 -D_GLIBCXX_ASSERTIONS -fasynchronous-unwind-tables"; break; case OPT_LEV_RELEASE: result += " -g0"; break; } + + if(config.getSanitize()) + { + result += " -fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined"; + } break; } case Compiler::MSVC: @@ -782,7 +787,10 @@ namespace backend case Compiler::GCC: { // TODO: Add flag to disable -ldl and -lm (dlopen, dlclose, floor, max, ...) - result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' -ldl -lm "; + result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed'"; + if(config.getSanitize()) + result += " -lasan -lubsan"; + result += " -ldl -lm "; break; } case Compiler::MSVC: @@ -848,7 +856,10 @@ namespace backend result += ".so: " + buildJob + " "; result += join(objectNames, " "); result += "\n"; - result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed' -ldl -lm "; + result += " LINK_ARGS = '-Wl,--no-undefined,--as-needed'"; + if(config.getSanitize()) + result += " -lasan -lubsan"; + result += " -ldl -lm "; projectGeneratedBinary += "lib" + config.getPackageName() + ".so"; break; } @@ -946,6 +957,7 @@ namespace backend FileType projectConfFileType = getFileType(projectConfFilePath.c_str()); SibsTestConfig sibsTestConfig(config.getCompiler(), testSourceDirNative, config.getOptimizationLevel()); + sibsTestConfig.setSanitize(config.getSanitize()); if(projectConfFileType == FileType::REGULAR) { Result result = Config::readFromFile(projectConfFilePath.c_str(), sibsTestConfig); diff --git a/include/Conf.hpp b/include/Conf.hpp index 6018b48..c8c22e1 100644 --- a/include/Conf.hpp +++ b/include/Conf.hpp @@ -213,7 +213,8 @@ namespace sibs buildTests(_buildTests), cVersion(CVersion::C11), cppVersion(CPPVersion::CPP14), - mainProject(false) + mainProject(false), + sanitize(false) { cmakeDirGlobal = projectPath; cmakeDirStatic = cmakeDirGlobal; @@ -388,6 +389,16 @@ namespace sibs this->mainProject = mainProject; } + bool getSanitize() const + { + return sanitize; + } + + void setSanitize(bool sanitize) + { + this->sanitize = sanitize; + } + virtual bool isDefined(const std::string &name) const; virtual bool define(const std::string &name, const std::string &value); virtual const std::unordered_map& getDefines() const; @@ -440,6 +451,7 @@ namespace sibs bool buildTests; bool finishedProcessing; bool mainProject; + bool sanitize; }; class SibsTestConfig : public SibsConfig diff --git a/sibs_multilib.kdev4 b/sibs_multilib.kdev4 new file mode 100644 index 0000000..298eb30 --- /dev/null +++ b/sibs_multilib.kdev4 @@ -0,0 +1,4 @@ +[Project] +CreatedFrom= +Manager=KDevCustomBuildSystem +Name=sibs_multilib diff --git a/src/CmakeModule.cpp b/src/CmakeModule.cpp index 15597cb..27047ba 100644 --- a/src/CmakeModule.cpp +++ b/src/CmakeModule.cpp @@ -121,6 +121,14 @@ namespace sibs return createBuildDirResult; FileString cmd = TINYDIR_STRING("cmake "); + if(config.getCompiler() == Compiler::GCC) + { + if(config.getSanitize()) + { + cmd += TINYDIR_STRING(" \"-CMAKE_C_FLAGS=-fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -lasan -lubsan\" " + "\"-CMAKE_CXX_FLAGS=-fno-omit-frame-pointer -fsanitize=address -fsanitize=undefined -lasan -lubsan\""); + } + } switch(config.getPackageType()) { case PackageType::EXECUTABLE: diff --git a/src/main.cpp b/src/main.cpp index db57648..134d2c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,16 +108,18 @@ void usage() void usageBuild() { - printf("Usage: sibs build [project_path] [--debug|--release]\n\n"); + printf("Usage: sibs build [project_path] [--debug|--release] [--sanitize]\n\n"); printf("Build a sibs project\n\n"); printf("Options:\n"); - printf(" project_path\t\t The directory containing a project.conf file - Optional (default: current working directory)\n"); + printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current working directory)\n"); printf(" --debug|--release\t\tOptimization level to build project and dependencies with (if not a system package) - Optional (default: --debug)\n"); + printf(" --sanitize\t\tAdd runtime address/undefined behavior sanitization. Program can be up to 3 times slower and use 3 times as much RAM. Ignored if compiler doesn't support sanitization - Optional (default: disabled)\n"); printf("Examples:\n"); printf(" sibs build\n"); printf(" sibs build dirA/dirB\n"); printf(" sibs build --release\n"); printf(" sibs build dirA --release\n"); + printf(" sibs build --sanitize\n"); exit(1); } @@ -137,10 +139,11 @@ void usageNew() void usageTest() { - printf("Usage: sibs test [project_path]\n\n"); + printf("Usage: sibs test [project_path] [--no-sanitize]\n\n"); printf("Build and run tests for a sibs project\n\n"); printf("Options:\n"); - printf(" project_path\t\t The directory containing a project.conf file - Optional (default: current working directory)\n"); + printf(" project_path\t\tThe directory containing a project.conf file - Optional (default: current working directory)\n"); + printf(" --no-sanitize\t\tDisable runtime address/undefined behavior - Optional\n"); printf("Examples:\n"); printf(" sibs test\n"); printf(" sibs test dirA/dirB\n"); @@ -213,6 +216,7 @@ int buildProject(const FileString &projectPath, const FileString &projectConfFil // It's ok if `define` fails. It could fail if `main` has already been replaced by other tests somehow. sibsConfig.define("main", "sibs_lib_ignore_main"); sibsConfig.define("wmain", "sibs_lib_ignore_wmain"); + sibsConfig.define("WinMain", "sibs_lib_ignore_WinMain"); sibsConfig.setPackageType(PackageType::DYNAMIC); } @@ -279,11 +283,12 @@ int buildProject(const FileString &projectPath, const FileString &projectConfFil int buildProject(int argc, const _tinydir_char_t **argv) { - if(argc > 2) + if(argc > 3) usageBuild(); OptimizationLevel optimizationLevel = OPT_LEV_NONE; FileString projectPath; + bool sanitize = false; for(int i = 0; i < argc; ++i) { @@ -306,6 +311,15 @@ int buildProject(int argc, const _tinydir_char_t **argv) } optimizationLevel = OPT_LEV_RELEASE; } + else if(_tinydir_strcmp(arg, TINYDIR_STRING("--sanitize")) == 0) + { + sanitize = true; + } + else if(_tinydir_strncmp(arg, TINYDIR_STRING("--"), 2) == 0) + { + ferr << "Error: Invalid argument " << arg << endl; + usageBuild(); + } else { if(!projectPath.empty()) @@ -349,6 +363,7 @@ int buildProject(int argc, const _tinydir_char_t **argv) #endif SibsConfig sibsConfig(compiler, projectPath, optimizationLevel, false); + sibsConfig.setSanitize(sanitize); return buildProject(projectPath, projectConfFilePath, sibsConfig); } @@ -356,10 +371,32 @@ int testProject(int argc, const _tinydir_char_t **argv) { if(argc > 1) usageTest(); - + FileString projectPath; - if(argc == 1) - projectPath = argv[0]; + bool sanitize = true; + + for(int i = 0; i < argc; ++i) + { + const _tinydir_char_t *arg = argv[i]; + if(_tinydir_strcmp(arg, TINYDIR_STRING("--no-sanitize")) == 0) + { + sanitize = false; + } + else if(_tinydir_strncmp(arg, TINYDIR_STRING("--"), 2) == 0) + { + ferr << "Error: Invalid argument " << arg << endl; + usageTest(); + } + else + { + if(!projectPath.empty()) + { + ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl; + usageTest(); + } + projectPath = arg; + } + } // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found if(projectPath.empty()) @@ -390,6 +427,7 @@ int testProject(int argc, const _tinydir_char_t **argv) #endif SibsConfig sibsConfig(compiler, projectPath, OPT_LEV_DEBUG, true); + sibsConfig.setSanitize(sanitize); return buildProject(projectPath, projectConfFilePath, sibsConfig); } @@ -543,7 +581,7 @@ int wmain(int argc, const _tinydir_char_t **argv) } else { - ferr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl; + ferr << "Expected command to be either 'build', 'new' or 'test', was: " << arg << endl << endl; usage(); } } -- cgit v1.2.3