Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/matrix.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"include": [
{
"DOCKER_TAG": "2022.7.0",
"DOCKER_TAG": "2022.8.0",
"OPERATING_SYSTEM_TAG": "18.04",
"LLVM_VERSION_MAJOR": "10"
}
Expand Down
4 changes: 4 additions & 0 deletions docker/Dockerfile_base
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ RUN echo "check_certificate = off" > /etc/wgetrc
# We use C++ 17 for UnitTestBot, it is available in gcc-9; default gcc for ubuntu:18.04 is gcc-7
RUN add-apt-repository ppa:ubuntu-toolchain-r/test
RUN apt update && apt install -y --no-install-recommends gcc-9 g++-9
# Skip 32bits libs installation before LLVM compilation
RUN sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 100
RUN sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 100
RUN sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-9 100
Expand Down Expand Up @@ -209,6 +210,9 @@ RUN git clone -b klee_uclibc_v1.2 https://github.com/klee/klee-uclibc.git $UTBOT
WORKDIR $UTBOT_ALL/klee-uclibc
RUN ./configure --make-llvm-lib && make -j`nproc`

# Install 32bits libs AFTER LLVM compilation
RUN apt update && apt install -y --no-install-recommends gcc-multilib g++-multilib gcc-9-multilib g++-9-multilib

# Download library for access private members
RUN git clone https://github.com/martong/access_private.git $UTBOT_ALL/access_private

Expand Down
144 changes: 68 additions & 76 deletions server/src/KleeRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ void KleeRunner::runKlee(const std::vector<tests::TestMethod> &testMethods,
std::stringstream logStream;
if (LogUtils::isMaxVerbosity()) {
logStream << "Processing batch: ";
for (const auto &[methodName, bitcodeFile, sourceFilepath] : batch) {
logStream << methodName << ", ";
for (const auto &method : batch) {
logStream << method.methodName << ", ";
}
LOG_S(MAX) << logStream.str();
}
Expand Down Expand Up @@ -207,30 +207,18 @@ static void processMethod(MethodKtests &ktestChunk,
}
}

void KleeRunner::processBatchWithoutInteractive(const std::vector<tests::TestMethod> &testMethods,
tests::Tests &tests,
std::vector<tests::MethodKtests> &ktests) {
if (!tests.isFilePresentedInArtifact || testMethods.empty()) {
return;
}

for (const auto &testMethod : testMethods) {
if (testMethod.sourceFilePath != tests.sourceFilePath) {
std::string message = StringUtils::stringFormat(
"While generating tests for source file: %s tried to generate tests for method %s "
"from another source file: %s. This can cause invalid generation.\n",
tests.sourceFilePath, testMethod.methodName, testMethod.sourceFilePath);
LOG_S(WARNING) << message;
}

std::string entryPoint = KleeUtils::entryPointFunction(tests, testMethod.methodName, true);
std::string entryPointFlag = StringUtils::stringFormat("--entry-point=%s", entryPoint);
auto kleeOut = Paths::kleeOutDirForEntrypoints(projectContext, projectTmpPath, testMethod.sourceFilePath,
testMethod.methodName);
std::pair<std::vector<std::string>, fs::path>
KleeRunner::createKleeParams(const tests::TestMethod &testMethod,
const tests::Tests &tests,
const std::string &methodNameOrEmptyForFolder) {
fs::path kleeOut = Paths::kleeOutDirForEntrypoints(projectContext,
projectTmpPath,
tests.sourceFilePath,
methodNameOrEmptyForFolder);
fs::create_directories(kleeOut.parent_path());
std::string outputDir = "--output-dir=" + kleeOut.string();

std::vector<std::string> argvData = { "klee",
entryPointFlag,
"--entry-point=" + KleeUtils::entryPointFunction(tests, testMethod.methodName, true),
"--libc=klee",
"--utbot",
"--posix-runtime",
Expand All @@ -245,20 +233,49 @@ void KleeRunner::processBatchWithoutInteractive(const std::vector<tests::TestMet
"--check-div-zero=false",
"--check-overshift=false",
"--skip-not-lazy-and-symbolic-pointers",
outputDir };
"--output-dir=" + kleeOut.string()};
if (settingsContext.useDeterministicSearcher) {
argvData.emplace_back("--search=dfs");
}
argvData.push_back(testMethod.bitcodeFilePath);
if (testMethod.is32bit) {
// 32bit project
argvData.emplace_back("--allocate-determ-size=" + std::to_string(1));
argvData.emplace_back("--allocate-determ-start-address=" + std::to_string(0x10000));
}
return {argvData, kleeOut};
}

void KleeRunner::addTailKleeInitParams(std::vector<std::string> &argvData, const std::string &bitcodeFilePath)
{
argvData.emplace_back(bitcodeFilePath);
argvData.emplace_back("--sym-stdin");
argvData.emplace_back(std::to_string(types::Type::symStdinSize));
}

{
std::vector<char *> cargv, cenvp;
std::vector<std::string> tmp;
ExecUtils::toCArgumentsPtr(argvData, tmp, cargv, cenvp, false);
LOG_S(DEBUG) << "Klee command :: " + StringUtils::joinWith(argvData, " ");
MEASURE_FUNCTION_EXECUTION_TIME
void KleeRunner::processBatchWithoutInteractive(const std::vector<tests::TestMethod> &testMethods,
tests::Tests &tests,
std::vector<tests::MethodKtests> &ktests) {
if (!tests.isFilePresentedInArtifact || testMethods.empty()) {
return;
}

for (const auto &testMethod : testMethods) {
if (testMethod.sourceFilePath != tests.sourceFilePath) {
std::string message = StringUtils::stringFormat(
"While generating tests for source file: %s tried to generate tests for method %s "
"from another source file: %s. This can cause invalid generation.\n",
tests.sourceFilePath, testMethod.methodName, testMethod.sourceFilePath);
LOG_S(WARNING) << message;
}

auto [argvData, kleeOut] = createKleeParams(testMethod, tests, testMethod.methodName);
addTailKleeInitParams(argvData, testMethod.bitcodeFilePath);
{
std::vector<char *> cargv, cenvp;
std::vector<std::string> tmp;
ExecUtils::toCArgumentsPtr(argvData, tmp, cargv, cenvp, false);
LOG_S(ERROR) << "Klee command :: " + StringUtils::joinWith(argvData, " ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change log level

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

MEASURE_FUNCTION_EXECUTION_TIME

RunKleeTask task(cargv.size(), cargv.data(), settingsContext.timeoutPerFunction);
ExecUtils::ExecutionResult result __attribute__((unused)) = task.run();
Expand Down Expand Up @@ -288,51 +305,26 @@ void KleeRunner::processBatchWithInteractive(const std::vector<tests::TestMethod
}
}

TestMethod testMethod = testMethods[0];
std::string entryPoint = KleeUtils::entryPointFunction(tests, testMethod.methodName, true);
std::string entryPointFlag = StringUtils::stringFormat("--entry-point=%s", entryPoint);
auto kleeOut = Paths::kleeOutDirForEntrypoints(projectContext, projectTmpPath, tests.sourceFilePath);
fs::create_directories(kleeOut.parent_path());

fs::path entrypoints = kleeOut.parent_path() / "entrypoints.txt";
std::ofstream of(entrypoints);
for (const auto &method : testMethods) {
of << KleeUtils::entryPointFunction(tests, method.methodName, true) << std::endl;
}
of.close();
std::string entrypointsArg = "--entrypoints-file=" + entrypoints.string();

std::string outputDir = "--output-dir=" + kleeOut.string();
std::vector<std::string> argvData = { "klee",
entryPointFlag,
"--libc=klee",
"--utbot",
"--posix-runtime",
"--fp-runtime",
"--only-output-states-covering-new",
"--allocate-determ",
"--external-calls=all",
"--timer-interval=1000ms",
"--bcov-check-interval=6s",
"-istats-write-interval=5s",
"--disable-verify",
"--check-div-zero=false",
"--check-overshift=false",
"--skip-not-lazy-and-symbolic-pointers",
"--interactive",
KleeUtils::processNumberOption(),
entrypointsArg,
outputDir };
if (settingsContext.timeoutPerFunction.has_value()) {
argvData.push_back(StringUtils::stringFormat("--timeout-per-function=%d", settingsContext.timeoutPerFunction.value()));
}
if (settingsContext.useDeterministicSearcher) {
argvData.emplace_back("--search=dfs");
auto [argvData, kleeOut] = createKleeParams(testMethods[0], tests, "");
{
// additional KLEE arguments
argvData.emplace_back("--interactive");
argvData.emplace_back(KleeUtils::processNumberOption());
{
// entrypoints
fs::path entrypoints = kleeOut.parent_path() / "entrypoints.txt";
std::ofstream of(entrypoints);
for (const auto &method : testMethods) {
of << KleeUtils::entryPointFunction(tests, method.methodName, true) << std::endl;
}
argvData.emplace_back("--entrypoints-file=" + entrypoints.string());
}
if (settingsContext.timeoutPerFunction.has_value()) {
argvData.emplace_back(StringUtils::stringFormat(
"--timeout-per-function=%d", settingsContext.timeoutPerFunction.value()));
}
addTailKleeInitParams(argvData, testMethods[0].bitcodeFilePath);
}
argvData.push_back(testMethod.bitcodeFilePath);
argvData.emplace_back("--sym-stdin");
argvData.emplace_back(std::to_string(types::Type::symStdinSize));

{
std::vector<char *> cargv, cenvp;
std::vector<std::string> tmp;
Expand Down
8 changes: 8 additions & 0 deletions server/src/KleeRunner.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ class KleeRunner {
void processBatchWithInteractive(const std::vector<tests::TestMethod> &testMethods,
tests::Tests &tests,
std::vector<tests::MethodKtests> &ktests);

std::pair<std::vector<std::string>, fs::path>
createKleeParams(const tests::TestMethod &testMethod,
const tests::Tests &tests,
const std::string &methodNameOrEmptyForFolder);

void addTailKleeInitParams(std::vector<std::string> &argvData,
const std::string &bitcodeFilePath);
};


Expand Down
11 changes: 7 additions & 4 deletions server/src/Paths.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,14 @@ namespace Paths {
return kleeOutDir / relative;
}

fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext, const fs::path &projectTmpPath,
const fs::path &srcFilePath, const std::string &methodName) {
fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext,
const fs::path &projectTmpPath,
const fs::path &srcFilePath,
const std::string &methodNameOrEmptyForFolder) {
auto kleeOutDirForFile = kleeOutDirForFilePath(projectContext, projectTmpPath, srcFilePath);
std::string suffix = methodName.empty() ?
addOrigExtensionAsSuffixAndAddNew(srcFilePath, "").filename().string() : methodName;
std::string suffix = methodNameOrEmptyForFolder.empty()
? addOrigExtensionAsSuffixAndAddNew(srcFilePath, "").filename().string()
: methodNameOrEmptyForFolder;
return kleeOutDirForFile / ("klee_out_" + suffix);
}

Expand Down
6 changes: 4 additions & 2 deletions server/src/Paths.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,10 @@ namespace Paths {
fs::path kleeOutDirForFilePath(const utbot::ProjectContext &projectContext, const fs::path &projectTmpPath,
const fs::path &filePath);

fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext, const fs::path &projectTmpPath,
const fs::path &srcFilePath, const std::string &methodName = "");
fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext,
const fs::path &projectTmpPath,
const fs::path &srcFilePath,
const std::string &methodNameOrEmptyForFolder);

//endregion

Expand Down
4 changes: 2 additions & 2 deletions server/src/SARIFGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ namespace sarif {
const fs::path &srcPath = fs::path(stack_match[3]);
const fs::path &relPathInProject = getInProjectPath(projectContext.projectPath, srcPath);
const fs::path &fullPathInProject = projectContext.projectPath / relPathInProject;
if (Paths::isSubPathOf(projectContext.buildDir(), fullPathInProject)) {
LOG_S(DEBUG) << "Full path " << fullPathInProject << " is in build - skip it";
if (Paths::isSubPathOf(Paths::getUtbotBuildDir(projectContext), fullPathInProject)) {
LOG_S(WARNING) << "Full path " << fullPathInProject << " is in build - skip it";
continue;
}
if (!relPathInProject.empty() && fs::exists(fullPathInProject)) {
Expand Down
13 changes: 8 additions & 5 deletions server/src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,13 +1137,16 @@ UnionValueView::UnionValueView(
entryValue(PrinterUtils::convertBytesToUnion(typeName, rawDataView->getEntryValue(nullptr))) {
}

TestMethod::TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename)
: methodName(std::move(methodName)), bitcodeFilePath(std::move(bitcodeFile)),
sourceFilePath(std::move(sourceFilename)) {
}
TestMethod::TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename, bool is32)
: methodName(std::move(methodName))
, bitcodeFilePath(std::move(bitcodeFile))
, sourceFilePath(std::move(sourceFilename))
, is32bit(is32)
{}

bool TestMethod::operator==(const TestMethod &rhs) const {
return std::tie(methodName, bitcodeFilePath, sourceFilePath) == std::tie(rhs.methodName, rhs.bitcodeFilePath, rhs.sourceFilePath);
return std::tie( methodName, bitcodeFilePath, sourceFilePath, is32bit)
== std::tie(rhs.methodName, rhs.bitcodeFilePath, rhs.sourceFilePath, rhs.is32bit);
}
bool TestMethod::operator!=(const TestMethod &rhs) const {
return !(rhs == *this);
Expand Down
4 changes: 3 additions & 1 deletion server/src/Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -557,10 +557,12 @@ namespace tests {
std::string methodName;
fs::path bitcodeFilePath;
fs::path sourceFilePath;
bool is32bit;

bool operator==(const TestMethod &rhs) const;
bool operator!=(const TestMethod &rhs) const;

TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename);
TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename, bool is32);
};

using MethodKtests = std::unordered_map<TestMethod, UTBotKTestList, HashUtils::TestMethodHash>;
Expand Down
4 changes: 4 additions & 0 deletions server/src/building/BuildDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,10 @@ void BuildDatabase::ObjectFileInfo::addFile(fs::path file) {
files.insert(std::move(file));
}

bool BuildDatabase::ObjectFileInfo::is32bit() const {
return CollectionUtils::contains(command.getCommandLine(), "-m32");
}

void BuildDatabase::TargetInfo::addFile(fs::path file) {
files.insert(std::move(file));
}
Expand Down
2 changes: 2 additions & 0 deletions server/src/building/BuildDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class BuildDatabase {
// User object file
[[nodiscard]] fs::path getOutputFile() const;

[[nodiscard]] bool is32bit() const;

void setOutputFile(const fs::path &file);

void addFile(fs::path file) override;
Expand Down
8 changes: 6 additions & 2 deletions server/src/building/Linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,10 @@ std::vector<tests::TestMethod> Linker::getTestMethods() {
auto compilationUnitInfo =
testGen.buildDatabase->getClientCompilationUnitInfo(fileName);
if (compilationUnitInfo->kleeFilesInfo->isCorrectMethod(methodName)) {
testMethods.emplace_back(methodName, bitcodePath, fileName);
testMethods.emplace_back(methodName,
bitcodePath,
fileName,
compilationUnitInfo->is32bit());
}
}
}
Expand All @@ -294,7 +297,8 @@ std::vector<tests::TestMethod> Linker::getTestMethods() {
if (compilationUnitInfo->kleeFilesInfo->isCorrectMethod(methodName)) {
tests::TestMethod testMethod{ methodName,
bitcodeFileName.at(lineInfo->filePath),
fileName };
fileName,
compilationUnitInfo->is32bit()};
testMethods.emplace_back(testMethod);
}
if (!lineInfo->forClass)
Expand Down
5 changes: 4 additions & 1 deletion server/src/utils/HashUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ namespace HashUtils {

std::size_t TestMethodHash::operator()(const tests::TestMethod &testMethod) const {
size_t seed = 0;
hashCombine(seed, testMethod.methodName, testMethod.bitcodeFilePath, testMethod.sourceFilePath);
hashCombine(seed, testMethod.methodName,
testMethod.bitcodeFilePath,
testMethod.sourceFilePath,
testMethod.is32bit);
return seed;
}
}