From 34ff3e3594bbb4a6f7b6a06b1bdcc8d49ff89595 Mon Sep 17 00:00:00 2001 From: Vladislav Kalugin Date: Thu, 13 Apr 2023 19:17:08 +0300 Subject: [PATCH] Link functions from libs only if needed --- include/klee/Core/Interpreter.h | 7 +- include/klee/Module/KModule.h | 2 +- include/klee/Support/ModuleUtil.h | 29 +++- lib/Core/Executor.cpp | 38 ++--- lib/Core/Executor.h | 3 +- lib/Module/KModule.cpp | 20 ++- lib/Module/ModuleUtil.cpp | 164 ++++------------------ lib/Module/RaiseAsm.cpp | 5 + lib/Runner/run_klee.cpp | 156 ++++++++++---------- test/regression/2023-03-27-lib-function.c | 32 +++++ 10 files changed, 203 insertions(+), 253 deletions(-) create mode 100644 test/regression/2023-03-27-lib-function.c diff --git a/include/klee/Core/Interpreter.h b/include/klee/Core/Interpreter.h index aa74b2641c..dde7f8fa43 100644 --- a/include/klee/Core/Interpreter.h +++ b/include/klee/Core/Interpreter.h @@ -102,12 +102,15 @@ class Interpreter { InterpreterHandler *ih); /// Register the module to be executed. - /// \param modules A list of modules that should form the final + /// \param userModules A list of user modules that should form the final + /// module + /// \param libsModules A list of libs modules that should form the final /// module /// \return The final module after it has been optimized, checks /// inserted, and modified for interpretation. virtual llvm::Module * - setModule(std::vector> &modules, + setModule(std::vector> &userModules, + std::vector> &libsModules, const ModuleOptions &opts, const std::vector &mainModuleFunctions) = 0; diff --git a/include/klee/Module/KModule.h b/include/klee/Module/KModule.h index 4a1f6400fc..6b496f3377 100644 --- a/include/klee/Module/KModule.h +++ b/include/klee/Module/KModule.h @@ -234,7 +234,7 @@ class KModule { /// @return true if at least one module has been linked in, false if nothing /// changed bool link(std::vector> &modules, - const std::string &entryPoint); + const unsigned flag); void instrument(const Interpreter::ModuleOptions &opts); diff --git a/include/klee/Support/ModuleUtil.h b/include/klee/Support/ModuleUtil.h index 714b6d5237..65be8b51ba 100644 --- a/include/klee/Support/ModuleUtil.h +++ b/include/klee/Support/ModuleUtil.h @@ -34,14 +34,14 @@ namespace klee { /// everything is linked against the first entry. /// @param entryFunction if set, missing functions of the module containing the /// entry function will be solved. -/// @return final module or null in this case errorMsg is set -std::unique_ptr -linkModules(std::vector> &modules, - llvm::StringRef entryFunction, std::string &errorMsg); +/// @return false in this case errorMsg is set +bool linkModules(llvm::Module *composite, + std::vector> &modules, + const unsigned Flags, std::string &errorMsg); #if defined(__x86_64__) || defined(__i386__) #define addFunctionReplacement(from, to) \ - {#from "f", #to "f"}, {#from, #to}, { "" #from "l", #to "l" } + {#from "f", #to "f"}, {#from "", #to ""}, { "" #from "l", #to "l" } #define addIntrinsicReplacement(from, to) \ {"llvm." #from ".f32", #to "f"}, {"llvm." #from ".f64", #to}, { \ @@ -119,6 +119,7 @@ bool functionEscapes(const llvm::Function *f); /// * .a archive containing .bc and .ll files /// /// @param libraryName library to read +/// @param context module context /// @param modules contains extracted modules /// @param errorMsg contains the error description in case the file could not be /// loaded @@ -126,6 +127,24 @@ bool functionEscapes(const llvm::Function *f); bool loadFile(const std::string &libraryName, llvm::LLVMContext &context, std::vector> &modules, std::string &errorMsg); + +/// Loads the file libraryName and reads all modules into one. +/// +/// Different file types are possible: +/// * .bc binary file +/// * .ll IR file +/// * .a archive containing .bc and .ll files +/// +/// @param libraryName library to read +/// @param context module context +/// @param modules contains extracted modules +/// @param errorMsg contains the error description in case the file could not be +/// loaded +/// @return true if successful otherwise false +bool loadFileAsOneModule(const std::string &libraryName, + llvm::LLVMContext &context, + std::vector> &modules, + std::string &errorMsg); } // namespace klee #endif /* KLEE_MODULEUTIL_H */ diff --git a/lib/Core/Executor.cpp b/lib/Core/Executor.cpp index 08ca1bb5d6..3eed4642da 100644 --- a/lib/Core/Executor.cpp +++ b/lib/Core/Executor.cpp @@ -102,6 +102,7 @@ typedef unsigned TypeSize; #include #include #include +#include #include #include #include @@ -542,29 +543,34 @@ Executor::Executor(LLVMContext &ctx, const InterpreterOptions &opts, } llvm::Module * -Executor::setModule(std::vector> &modules, +Executor::setModule(std::vector> &userModules, + std::vector> &libsModules, const ModuleOptions &opts, const std::vector &mainModuleFunctions) { - assert(!kmodule && !modules.empty() && + assert(!kmodule && !userModules.empty() && "can only register one module"); // XXX gross - kmodule = std::unique_ptr(new KModule()); + kmodule = std::make_unique(); - // Preparing the final module happens in multiple stages + // 1.) Link the modules together && 2.) Apply different instrumentation + kmodule->link(userModules, 0); + kmodule->instrument(opts); - // Link with KLEE intrinsics library before running any optimizations - SmallString<128> LibPath(opts.LibraryDir); - llvm::sys::path::append(LibPath, - "libkleeRuntimeIntrinsic" + opts.OptSuffix + ".bca"); - std::string error; - if (!klee::loadFile(LibPath.c_str(), modules[0]->getContext(), modules, - error)) { - klee_error("Could not load KLEE intrinsic file %s", LibPath.c_str()); - } + kmodule->link(libsModules, 2); + kmodule->instrument(opts); - // 1.) Link the modules together - while (kmodule->link(modules, opts.EntryPoint)) { - // 2.) Apply different instrumentation + { + std::vector> modules; + // Link with KLEE intrinsics library before running any optimizations + SmallString<128> LibPath(opts.LibraryDir); + llvm::sys::path::append(LibPath, "libkleeRuntimeIntrinsic" + + opts.OptSuffix + ".bca"); + std::string error; + if (!klee::loadFileAsOneModule( + LibPath.c_str(), kmodule->module->getContext(), modules, error)) { + klee_error("Could not load KLEE intrinsic file %s", LibPath.c_str()); + } + kmodule->link(modules, 2); kmodule->instrument(opts); } diff --git a/lib/Core/Executor.h b/lib/Core/Executor.h index d7304561ed..2c94a3eae0 100644 --- a/lib/Core/Executor.h +++ b/lib/Core/Executor.h @@ -541,7 +541,8 @@ class Executor : public Interpreter { } llvm::Module * - setModule(std::vector> &modules, + setModule(std::vector> &userModules, + std::vector> &libsModules, const ModuleOptions &opts, const std::vector &mainModuleFunctions) override; diff --git a/lib/Module/KModule.cpp b/lib/Module/KModule.cpp index ccd69cf63f..889b5e3a6a 100644 --- a/lib/Module/KModule.cpp +++ b/lib/Module/KModule.cpp @@ -221,20 +221,18 @@ void KModule::addInternalFunction(const char *functionName) { } bool KModule::link(std::vector> &modules, - const std::string &entryPoint) { - auto numRemainingModules = modules.size(); - // Add the currently active module to the list of linkables - modules.push_back(std::move(module)); + unsigned flags) { std::string error; - module = std::unique_ptr( - klee::linkModules(modules, entryPoint, error)); - if (!module) + if (!module) { + module = std::move(modules.front()); + } + if (!klee::linkModules(module.get(), modules, flags, error)) { klee_error("Could not link KLEE files %s", error.c_str()); + return false; + } - targetData = std::unique_ptr(new DataLayout(module.get())); - - // Check if we linked anything - return modules.size() != numRemainingModules; + targetData = std::make_unique(module.get()); + return true; } void KModule::replaceFunction(const std::unique_ptr &m, diff --git a/lib/Module/ModuleUtil.cpp b/lib/Module/ModuleUtil.cpp index e7626e58a6..b0cbffbb57 100644 --- a/lib/Module/ModuleUtil.cpp +++ b/lib/Module/ModuleUtil.cpp @@ -133,153 +133,24 @@ static void GetAllUndefinedSymbols(Module *M, << "*** Finished computing undefined symbols ***\n"); } -static bool linkTwoModules(llvm::Module *Dest, - std::unique_ptr Src, - std::string &errorMsg) { - // Get the potential error message (Src is moved and won't be available later) - errorMsg = "Linking module " + Src->getModuleIdentifier() + " failed"; - auto linkResult = Linker::linkModules(*Dest, std::move(Src)); - - return !linkResult; -} - -std::unique_ptr -klee::linkModules(std::vector> &modules, - llvm::StringRef entryFunction, std::string &errorMsg) { - assert(!modules.empty() && "modules list should not be empty"); - - if (entryFunction.empty()) { - // If no entry function is provided, link all modules together into one - std::unique_ptr composite = std::move(modules.back()); - modules.pop_back(); - - // Just link all modules together - for (auto &module : modules) { - if (linkTwoModules(composite.get(), std::move(module), errorMsg)) - continue; - - // Linking failed - errorMsg = "Linking archive module with composite failed:" + errorMsg; - return nullptr; - } - - // clean up every module as we already linked in every module - modules.clear(); - return composite; - } - - // Starting from the module containing the entry function, resolve unresolved - // dependencies recursively +bool klee::linkModules(llvm::Module *composite, + std::vector> &modules, + const unsigned flags, std::string &errorMsg) { + // assert(composite); - // search for the module containing the entry function - std::unique_ptr composite; + Linker linker(*composite); for (auto &module : modules) { - if (!module || !module->getNamedValue(entryFunction)) + if (!module) continue; - if (composite) { - errorMsg = - "Function " + entryFunction.str() + - " defined in different modules (" + module->getModuleIdentifier() + - " already defined in: " + composite->getModuleIdentifier() + ")"; - return nullptr; - } - composite = std::move(module); - } - - // fail if not found - if (!composite) { - errorMsg = - "Entry function '" + entryFunction.str() + "' not found in module."; - return nullptr; - } - - auto containsUsedSymbols = [](const llvm::Module *module) { - GlobalValue *GV = - dyn_cast_or_null(module->getNamedValue("llvm.used")); - if (!GV) - return false; - KLEE_DEBUG_WITH_TYPE("klee_linker", dbgs() << "Used attribute in " - << module->getModuleIdentifier() - << '\n'); - return true; - }; - - for (auto &module : modules) { - if (!module || !containsUsedSymbols(module.get())) - continue; - - if (!linkTwoModules(composite.get(), std::move(module), errorMsg)) { + errorMsg = "Linking module " + module->getModuleIdentifier() + " failed"; + if (linker.linkInModule(std::move(module), flags)) { // Linking failed - errorMsg = "Linking module containing '__attribute__((used))'" - " symbols with composite failed:" + - errorMsg; - return nullptr; - } - module = nullptr; - } - - bool symbolsLinked = true; - while (symbolsLinked) { - symbolsLinked = false; - std::set undefinedSymbols; - GetAllUndefinedSymbols(composite.get(), undefinedSymbols); - auto hasRequiredDefinition = [&undefinedSymbols]( - const llvm::Module *module) { - for (auto symbol : undefinedSymbols) { - GlobalValue *GV = - dyn_cast_or_null(module->getNamedValue(symbol)); - if (GV && !GV->isDeclaration()) { - KLEE_DEBUG_WITH_TYPE("klee_linker", - dbgs() << "Found " << GV->getName() << " in " - << module->getModuleIdentifier() << "\n"); - return true; - } - } + errorMsg = "Linking archive module with composite failed:" + errorMsg; return false; - }; - - // replace std functions with KLEE internals - for (const auto &p : floatReplacements) { - if (composite->getFunction(p.first)) { - undefinedSymbols.insert(p.second); - } - } - for (const auto &p : feRoundReplacements) { - if (composite->getFunction(p.first)) { - undefinedSymbols.insert(p.second); - } } - - // Stop in nothing is undefined - if (undefinedSymbols.empty()) - break; - - for (auto &module : modules) { - if (!module) - continue; - - if (!hasRequiredDefinition(module.get())) - continue; - - if (!linkTwoModules(composite.get(), std::move(module), errorMsg)) { - // Linking failed - errorMsg = "Linking archive module with composite failed:" + errorMsg; - return nullptr; - } - module = nullptr; - symbolsLinked = true; - } - } - - // Condense the module array - std::vector> LeftoverModules; - for (auto &module : modules) { - if (module) - LeftoverModules.emplace_back(std::move(module)); } - - modules.swap(LeftoverModules); - return composite; + modules.clear(); + return true; } Function *klee::getDirectCallTarget( @@ -496,3 +367,16 @@ bool klee::loadFile(const std::string &fileName, LLVMContext &context, modules.push_back(std::move(module)); return true; } + +bool klee::loadFileAsOneModule( + const std::string &libraryName, LLVMContext &context, + std::vector> &modules, + std::string &errorMsg) { + std::vector> modules2; + bool res = klee::loadFile(libraryName, context, modules2, errorMsg); + if (res) { + modules.push_back(std::move(modules2.front())); + return linkModules(modules.back().get(), modules2, 0, errorMsg); + } + return res; +} diff --git a/lib/Module/RaiseAsm.cpp b/lib/Module/RaiseAsm.cpp index cc3b16e5d1..e1afdc4917 100644 --- a/lib/Module/RaiseAsm.cpp +++ b/lib/Module/RaiseAsm.cpp @@ -74,6 +74,11 @@ bool RaiseAsmPass::runOnInstruction(Module &M, Instruction *I) { bool RaiseAsmPass::runOnModule(Module &M) { bool changed = false; + + if (M.empty()) { + return false; + } + std::string Err; // Use target triple from the module if possible. diff --git a/lib/Runner/run_klee.cpp b/lib/Runner/run_klee.cpp index e4480faf41..74f04438dc 100644 --- a/lib/Runner/run_klee.cpp +++ b/lib/Runner/run_klee.cpp @@ -755,31 +755,21 @@ static void parseArguments(int argc, char **argv) { } static void -preparePOSIX(std::vector> &loadedModules, - llvm::StringRef libCPrefix) { +preparePOSIX(std::vector> &loadedModules) { // Get the main function from the main module and rename it such that it can // be called after the POSIX setup Function *mainFn = nullptr; for (auto &module : loadedModules) { mainFn = module->getFunction(EntryPoint); - if (mainFn) + if (mainFn && !mainFn->empty()) break; } - if (!mainFn) { + if (!mainFn || mainFn->empty()) { klee_error("Entry function '%s' not found in module.", EntryPoint.c_str()); } mainFn->setName("__klee_posix_wrapped_main"); - // Add a definition of the entry function if needed. This is the case if we - // link against a libc implementation. Preparing for libc linking (i.e. - // linking with uClibc will expect a main function and rename it to - // _user_main. We just provide the definition here. - if (!libCPrefix.empty() && !mainFn->getParent()->getFunction(EntryPoint)) - llvm::Function::Create(mainFn->getFunctionType(), - llvm::Function::ExternalLinkage, EntryPoint, - mainFn->getParent()); - llvm::Function *wrapper = nullptr; for (auto &module : loadedModules) { wrapper = module->getFunction("__klee_posix_wrapper"); @@ -790,7 +780,9 @@ preparePOSIX(std::vector> &loadedModules, // Rename the POSIX wrapper to prefixed entrypoint, e.g. _user_main as uClibc // would expect it or main otherwise - wrapper->setName(libCPrefix + EntryPoint); + wrapper->setName(EntryPoint); + loadedModules.front()->getOrInsertFunction(wrapper->getName(), + wrapper->getFunctionType()); } // This is a terrible hack until we get some real modeling of the @@ -1056,7 +1048,8 @@ static void halt_via_gdb(int pid) { #ifndef SUPPORT_KLEE_UCLIBC static void linkWithUclibc(StringRef libDir, std::string opt_suffix, - std::vector> &modules) { + std::vector> &userModules, + std::vector> &libsModules) { klee_error("invalid libc, no uclibc support!\n"); } #else @@ -1077,7 +1070,8 @@ static void replaceOrRenameFunction(llvm::Module *module, const char *old_name, } static void -createLibCWrapper(std::vector> &modules, +createLibCWrapper(std::vector> &userModules, + std::vector> &libsModules, llvm::StringRef intendedFunction, llvm::StringRef libcMainFunction) { // XXX we need to rearchitect so this can also be used with @@ -1090,20 +1084,24 @@ createLibCWrapper(std::vector> &modules, // also an implicit cooperation in that runFunctionAsMain sets up // the environment arguments to what a libc expects (following // argv), since it does not explicitly take an envp argument. - auto &ctx = modules[0]->getContext(); - Function *userMainFn = modules[0]->getFunction(intendedFunction); + auto &ctx = userModules[0]->getContext(); + Function *userMainFn = nullptr; + for (auto &module : userModules) { + userMainFn = module->getFunction(intendedFunction); + if (userMainFn) { + // Rename entry point using a prefix + userMainFn->setName("__user_" + intendedFunction); + } + } if (!userMainFn) { klee_error("Entry function '%s' not found in module.", intendedFunction.str().c_str()); } - // Rename entry point using a prefix - userMainFn->setName("__user_" + intendedFunction); - // force import of libcMainFunction llvm::Function *libcMainFn = nullptr; - for (auto &module : modules) { + for (auto &module : libsModules) { if ((libcMainFn = module->getFunction(libcMainFunction))) break; } @@ -1147,46 +1145,47 @@ createLibCWrapper(std::vector> &modules, args.push_back(Constant::getNullValue(ft->getParamType(6))); // stack_end Builder.CreateCall(libcMainFn, args); Builder.CreateUnreachable(); + + userModules.front()->getOrInsertFunction(stub->getName(), + stub->getFunctionType()); } static void linkWithUclibc(StringRef libDir, std::string opt_suffix, - std::vector> &modules) { - LLVMContext &ctx = modules[0]->getContext(); + std::vector> &userModules, + std::vector> &libsModules) { + LLVMContext &ctx = userModules[0]->getContext(); + std::string errorMsg; - size_t newModules = modules.size(); + // Link the fortified library + SmallString<128> FortifyPath(libDir); + llvm::sys::path::append(FortifyPath, + "libkleeRuntimeFortify" + opt_suffix + ".bca"); + if (!klee::loadFileAsOneModule(FortifyPath.c_str(), ctx, libsModules, + errorMsg)) + klee_error("error loading the fortify library '%s': %s", + FortifyPath.c_str(), errorMsg.c_str()); // Ensure that klee-uclibc exists SmallString<128> uclibcBCA(libDir); - std::string errorMsg; llvm::sys::path::append(uclibcBCA, KLEE_UCLIBC_BCA_NAME); - if (!klee::loadFile(uclibcBCA.c_str(), ctx, modules, errorMsg)) + if (!klee::loadFileAsOneModule(uclibcBCA.c_str(), ctx, libsModules, errorMsg)) klee_error("Cannot find klee-uclibc '%s': %s", uclibcBCA.c_str(), errorMsg.c_str()); - for (auto i = newModules, j = modules.size(); i < j; ++i) { - replaceOrRenameFunction(modules[i].get(), "__libc_open", "open"); - replaceOrRenameFunction(modules[i].get(), "__libc_fcntl", "fcntl"); - } + replaceOrRenameFunction(libsModules.back().get(), "__libc_open", "open"); + replaceOrRenameFunction(libsModules.back().get(), "__libc_fcntl", "fcntl"); - createLibCWrapper(modules, EntryPoint, "__uClibc_main"); - klee_message("NOTE: Using klee-uclibc : %s", uclibcBCA.c_str()); + createLibCWrapper(userModules, libsModules, EntryPoint, "__uClibc_main"); - // Link the fortified library - SmallString<128> FortifyPath(libDir); - llvm::sys::path::append(FortifyPath, - "libkleeRuntimeFortify" + opt_suffix + ".bca"); - if (!klee::loadFile(FortifyPath.c_str(), ctx, modules, errorMsg)) - klee_error("error loading the fortify library '%s': %s", - FortifyPath.c_str(), errorMsg.c_str()); + klee_message("NOTE: Using klee-uclibc : %s", uclibcBCA.c_str()); } #endif -static int run_klee_on_function( - int pArgc, char **pArgv, char **pEnvp, KleeHandler *handler, - Interpreter *interpreter, llvm::Module *finalModule, - std::vector &replayPath, - std::vector> &loadedModules) { +static int run_klee_on_function(int pArgc, char **pArgv, char **pEnvp, + KleeHandler *handler, Interpreter *interpreter, + llvm::Module *finalModule, + std::vector &replayPath) { Function *mainFn = finalModule->getFunction(EntryPoint); if (!mainFn) { klee_error("Entry function '%s' not found in module.", EntryPoint.c_str()); @@ -1463,22 +1462,22 @@ int run_klee(int argc, char **argv, char **envp) { // Load the bytecode... std::string errorMsg; LLVMContext ctx; - std::vector> loadedModules; - if (!klee::loadFile(InputFile, ctx, loadedModules, errorMsg)) { + std::vector> loadedUserModules; + std::vector> loadedLibsModules; + if (!klee::loadFileAsOneModule(InputFile, ctx, loadedUserModules, errorMsg)) { klee_error("error loading program '%s': %s", InputFile.c_str(), errorMsg.c_str()); } // Load and link the whole files content. The assumption is that this is the // application under test. // Nothing gets removed in the first place. - std::unique_ptr M(klee::linkModules( - loadedModules, "" /* link all modules together */, errorMsg)); - if (!M) { + + if (!loadedUserModules.front()) { klee_error("error loading program '%s': %s", InputFile.c_str(), errorMsg.c_str()); } - llvm::Module *mainModule = M.get(); + llvm::Module *mainModule = loadedUserModules.front().get(); std::vector mainModuleFunctions; for (auto &Function : *mainModule) { @@ -1506,9 +1505,6 @@ int run_klee(int argc, char **argv, char **envp) { // Add additional user-selected suffix opt_suffix += "_" + RuntimeBuild.getValue(); - // Push the module as the first entry - loadedModules.emplace_back(std::move(M)); - std::string LibraryDir = KleeHandler::getRunTimeLibraryPath(argv[0]); Interpreter::ModuleOptions Opts(LibraryDir.c_str(), EntryPoint, opt_suffix, /*Optimize=*/OptimizeModule, @@ -1520,8 +1516,8 @@ int run_klee(int argc, char **argv, char **envp) { SmallString<128> Path(Opts.LibraryDir); llvm::sys::path::append(Path, "libkleeRuntimePOSIX" + opt_suffix + ".bca"); klee_message("NOTE: Using POSIX model: %s", Path.c_str()); - if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules, - errorMsg)) + if (!klee::loadFileAsOneModule(Path.c_str(), mainModule->getContext(), + loadedUserModules, errorMsg)) klee_error("error loading POSIX support '%s': %s", Path.c_str(), errorMsg.c_str()); @@ -1531,15 +1527,14 @@ int run_klee(int argc, char **argv, char **envp) { "libkleeRuntimeIO_C" + opt_suffix + ".bca"); klee_message("NOTE: using klee versions of input/output functions: %s", Path_io.c_str()); - if (!klee::loadFile(Path_io.c_str(), mainModule->getContext(), - loadedModules, errorMsg)) + if (!klee::loadFileAsOneModule(Path_io.c_str(), mainModule->getContext(), + loadedUserModules, errorMsg)) klee_error("error loading POSIX_IO support '%s': %s", Path_io.c_str(), errorMsg.c_str()); } if (!UTBotMode) { - std::string libcPrefix = (Libc == LibcType::UcLibc ? "__user_" : ""); - preparePOSIX(loadedModules, libcPrefix); + preparePOSIX(loadedUserModules); } } @@ -1547,8 +1542,8 @@ int run_klee(int argc, char **argv, char **envp) { #if ENABLE_FP SmallString<128> Path(Opts.LibraryDir); llvm::sys::path::append(Path, "libkleeRuntimeFp" + opt_suffix + ".bca"); - if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules, - errorMsg)) + if (!klee::loadFileAsOneModule(Path.c_str(), mainModule->getContext(), + loadedUserModules, errorMsg)) klee_error("error loading klee FP runtime '%s': %s", Path.c_str(), errorMsg.c_str()); #else @@ -1563,16 +1558,16 @@ int run_klee(int argc, char **argv, char **envp) { #else SmallString<128> LibcxxBC(Opts.LibraryDir); llvm::sys::path::append(LibcxxBC, KLEE_LIBCXX_BC_NAME); - if (!klee::loadFile(LibcxxBC.c_str(), mainModule->getContext(), - loadedModules, errorMsg)) + if (!klee::loadFileAsOneModule(LibcxxBC.c_str(), mainModule->getContext(), + loadedLibsModules, errorMsg)) klee_error("error loading libc++ '%s': %s", LibcxxBC.c_str(), errorMsg.c_str()); klee_message("NOTE: Using libc++ : %s", LibcxxBC.c_str()); #ifdef SUPPORT_KLEE_EH_CXX SmallString<128> EhCxxPath(Opts.LibraryDir); llvm::sys::path::append(EhCxxPath, "libkleeeh-cxx" + opt_suffix + ".bca"); - if (!klee::loadFile(EhCxxPath.c_str(), mainModule->getContext(), - loadedModules, errorMsg)) + if (!klee::loadFileAsOneModule(EhCxxPath.c_str(), mainModule->getContext(), + loadedLibsModules, errorMsg)) klee_error("error loading libklee-eh-cxx '%s': %s", EhCxxPath.c_str(), errorMsg.c_str()); klee_message("NOTE: Enabled runtime support for C++ exceptions"); @@ -1588,8 +1583,8 @@ int run_klee(int argc, char **argv, char **envp) { SmallString<128> Path(Opts.LibraryDir); llvm::sys::path::append(Path, "libkleeRuntimeKLEELibc" + opt_suffix + ".bca"); - if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules, - errorMsg)) + if (!klee::loadFileAsOneModule(Path.c_str(), mainModule->getContext(), + loadedLibsModules, errorMsg)) klee_error("error loading klee libc '%s': %s", Path.c_str(), errorMsg.c_str()); } @@ -1598,20 +1593,21 @@ int run_klee(int argc, char **argv, char **envp) { SmallString<128> Path(Opts.LibraryDir); llvm::sys::path::append(Path, "libkleeRuntimeFreestanding" + opt_suffix + ".bca"); - if (!klee::loadFile(Path.c_str(), mainModule->getContext(), loadedModules, - errorMsg)) + if (!klee::loadFileAsOneModule(Path.c_str(), mainModule->getContext(), + loadedLibsModules, errorMsg)) klee_error("error loading freestanding support '%s': %s", Path.c_str(), errorMsg.c_str()); break; } case LibcType::UcLibc: - linkWithUclibc(LibraryDir, opt_suffix, loadedModules); + linkWithUclibc(LibraryDir, opt_suffix, loadedUserModules, + loadedLibsModules); break; } for (const auto &library : LinkLibraries) { - if (!klee::loadFile(library, mainModule->getContext(), loadedModules, - errorMsg)) + if (!klee::loadFileAsOneModule(library, mainModule->getContext(), + loadedLibsModules, errorMsg)) klee_error("error loading bitcode library '%s': %s", library.c_str(), errorMsg.c_str()); } @@ -1677,8 +1673,14 @@ int run_klee(int argc, char **argv, char **envp) { // Get the desired main function. klee_main initializes uClibc // locale and other data and then calls main. - auto finalModule = - interpreter->setModule(loadedModules, Opts, mainModuleFunctions); + auto finalModule = interpreter->setModule( + loadedUserModules, loadedLibsModules, Opts, mainModuleFunctions); + Function *mainFn = finalModule->getFunction(EntryPoint); + if (!mainFn) { + klee_error("Entry function '%s' not found in module.", EntryPoint.c_str()); + } + + externalsAndGlobalsCheck(finalModule); if (InteractiveMode) { klee_message("KLEE finish preprocessing."); std::ifstream entrypoints(EntryPointsFile); @@ -1730,7 +1732,7 @@ int run_klee(int argc, char **argv, char **envp) { sys::path::append(newOutputDirectory, entrypoint); handler->setOutputDirectory(newOutputDirectory.c_str()); run_klee_on_function(pArgc, pArgv, pEnvp, handler, interpreter, - finalModule, replayPath, loadedModules); + finalModule, replayPath); exit(0); } else { child_processes.emplace_back(pid, std::chrono::steady_clock::now()); @@ -1753,7 +1755,7 @@ int run_klee(int argc, char **argv, char **envp) { } } else { run_klee_on_function(pArgc, pArgv, pEnvp, handler, interpreter, finalModule, - replayPath, loadedModules); + replayPath); } // Free all the args. diff --git a/test/regression/2023-03-27-lib-function.c b/test/regression/2023-03-27-lib-function.c new file mode 100644 index 0000000000..4754267431 --- /dev/null +++ b/test/regression/2023-03-27-lib-function.c @@ -0,0 +1,32 @@ +// RUN: %clang %s -g -emit-llvm -DINET_NTOP %O0opt -c -o %t1.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --exit-on-error --output-dir=%t.klee-out %t1.bc 2>&1 | FileCheck -check-prefix=CHECK_INTERNAL %s +// RUN: %clang %s -g -emit-llvm -DINET_NTOP -DINET_PTON %O0opt -c -o %t2.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --exit-on-error --output-dir=%t.klee-out %t2.bc 2>&1 | FileCheck -check-prefix=CHECK_INTERNAL %s +// RUN: %clang %s -g -emit-llvm %O0opt -c -o %t3.bc +// RUN: rm -rf %t.klee-out +// RUN: %klee --exit-on-error --output-dir=%t.klee-out %t3.bc 2>&1 | FileCheck -check-prefix=CHECK_EXTERNAL %s + +#include +#include + +#ifdef INET_NTOP +const char *inet_ntop(int af, const void *restrict src, + char *restrict dst, socklen_t size) { + printf("Hello\n"); + // CHECK_INTERNAL: Hello + return 0; +} +#endif + +int main(int argc, char **argv) { + inet_ntop(0, 0, 0, 0); + // CHECK_INTERNAL-NOT: calling external: inet_ntop + // CHECK_EXTERNAL: calling external: inet_ntop +#ifdef INET_PTON + struct in_addr inaddr; + inet_pton(AF_INET, "10.1.0.29", &inaddr); +#endif + return 0; +}