Skip to content

Commit 6d24365

Browse files
authored
#216 UTBotCpp does not support test generation for 32bit projects (#373)
* #216 UTBotCpp does not support test generation for 32bit projects - fix SARIF genetarion in tests (build dir :==: src dir) - fix 32bit libs installation: added `gcc-multilib` `g++-multilib` - fix the order of 32bit libs installation in docker (fixind LLVM compilation) - add 32bit libs for gcc-9 to support cross-compilation - for 32bit projects we change KLEE params from defaults: --allocate-determ-size: 100 -> 1 --allocate-determ-start-address: 0x7ff30000000 -> 0x10000
1 parent 9f7edaa commit 6d24365

File tree

13 files changed

+121
-94
lines changed

13 files changed

+121
-94
lines changed

.github/workflows/matrix.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"include": [
33
{
4-
"DOCKER_TAG": "2022.7.0",
4+
"DOCKER_TAG": "2022.8.0",
55
"OPERATING_SYSTEM_TAG": "18.04",
66
"LLVM_VERSION_MAJOR": "10"
77
}

docker/Dockerfile_base

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ RUN echo "check_certificate = off" > /etc/wgetrc
2424
# We use C++ 17 for UnitTestBot, it is available in gcc-9; default gcc for ubuntu:18.04 is gcc-7
2525
RUN add-apt-repository ppa:ubuntu-toolchain-r/test
2626
RUN apt update && apt install -y --no-install-recommends gcc-9 g++-9
27+
# Skip 32bits libs installation before LLVM compilation
2728
RUN sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 100
2829
RUN sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 100
2930
RUN sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-9 100
@@ -209,6 +210,9 @@ RUN git clone -b klee_uclibc_v1.2 https://github.com/klee/klee-uclibc.git $UTBOT
209210
WORKDIR $UTBOT_ALL/klee-uclibc
210211
RUN ./configure --make-llvm-lib && make -j`nproc`
211212

213+
# Install 32bits libs AFTER LLVM compilation
214+
RUN apt update && apt install -y --no-install-recommends gcc-multilib g++-multilib gcc-9-multilib g++-9-multilib
215+
212216
# Download library for access private members
213217
RUN git clone https://github.com/martong/access_private.git $UTBOT_ALL/access_private
214218

server/src/KleeRunner.cpp

Lines changed: 68 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ void KleeRunner::runKlee(const std::vector<tests::TestMethod> &testMethods,
9595
std::stringstream logStream;
9696
if (LogUtils::isMaxVerbosity()) {
9797
logStream << "Processing batch: ";
98-
for (const auto &[methodName, bitcodeFile, sourceFilepath] : batch) {
99-
logStream << methodName << ", ";
98+
for (const auto &method : batch) {
99+
logStream << method.methodName << ", ";
100100
}
101101
LOG_S(MAX) << logStream.str();
102102
}
@@ -207,30 +207,18 @@ static void processMethod(MethodKtests &ktestChunk,
207207
}
208208
}
209209

210-
void KleeRunner::processBatchWithoutInteractive(const std::vector<tests::TestMethod> &testMethods,
211-
tests::Tests &tests,
212-
std::vector<tests::MethodKtests> &ktests) {
213-
if (!tests.isFilePresentedInArtifact || testMethods.empty()) {
214-
return;
215-
}
216-
217-
for (const auto &testMethod : testMethods) {
218-
if (testMethod.sourceFilePath != tests.sourceFilePath) {
219-
std::string message = StringUtils::stringFormat(
220-
"While generating tests for source file: %s tried to generate tests for method %s "
221-
"from another source file: %s. This can cause invalid generation.\n",
222-
tests.sourceFilePath, testMethod.methodName, testMethod.sourceFilePath);
223-
LOG_S(WARNING) << message;
224-
}
225-
226-
std::string entryPoint = KleeUtils::entryPointFunction(tests, testMethod.methodName, true);
227-
std::string entryPointFlag = StringUtils::stringFormat("--entry-point=%s", entryPoint);
228-
auto kleeOut = Paths::kleeOutDirForEntrypoints(projectContext, projectTmpPath, testMethod.sourceFilePath,
229-
testMethod.methodName);
210+
std::pair<std::vector<std::string>, fs::path>
211+
KleeRunner::createKleeParams(const tests::TestMethod &testMethod,
212+
const tests::Tests &tests,
213+
const std::string &methodNameOrEmptyForFolder) {
214+
fs::path kleeOut = Paths::kleeOutDirForEntrypoints(projectContext,
215+
projectTmpPath,
216+
tests.sourceFilePath,
217+
methodNameOrEmptyForFolder);
230218
fs::create_directories(kleeOut.parent_path());
231-
std::string outputDir = "--output-dir=" + kleeOut.string();
219+
232220
std::vector<std::string> argvData = { "klee",
233-
entryPointFlag,
221+
"--entry-point=" + KleeUtils::entryPointFunction(tests, testMethod.methodName, true),
234222
"--libc=klee",
235223
"--utbot",
236224
"--posix-runtime",
@@ -245,20 +233,49 @@ void KleeRunner::processBatchWithoutInteractive(const std::vector<tests::TestMet
245233
"--check-div-zero=false",
246234
"--check-overshift=false",
247235
"--skip-not-lazy-and-symbolic-pointers",
248-
outputDir };
236+
"--output-dir=" + kleeOut.string()};
249237
if (settingsContext.useDeterministicSearcher) {
250238
argvData.emplace_back("--search=dfs");
251239
}
252-
argvData.push_back(testMethod.bitcodeFilePath);
240+
if (testMethod.is32bits) {
241+
// 32bit project
242+
argvData.emplace_back("--allocate-determ-size=" + std::to_string(1));
243+
argvData.emplace_back("--allocate-determ-start-address=" + std::to_string(0x10000));
244+
}
245+
return {argvData, kleeOut};
246+
}
247+
248+
void KleeRunner::addTailKleeInitParams(std::vector<std::string> &argvData, const std::string &bitcodeFilePath)
249+
{
250+
argvData.emplace_back(bitcodeFilePath);
253251
argvData.emplace_back("--sym-stdin");
254252
argvData.emplace_back(std::to_string(types::Type::symStdinSize));
253+
}
255254

256-
{
257-
std::vector<char *> cargv, cenvp;
258-
std::vector<std::string> tmp;
259-
ExecUtils::toCArgumentsPtr(argvData, tmp, cargv, cenvp, false);
260-
LOG_S(DEBUG) << "Klee command :: " + StringUtils::joinWith(argvData, " ");
261-
MEASURE_FUNCTION_EXECUTION_TIME
255+
void KleeRunner::processBatchWithoutInteractive(const std::vector<tests::TestMethod> &testMethods,
256+
tests::Tests &tests,
257+
std::vector<tests::MethodKtests> &ktests) {
258+
if (!tests.isFilePresentedInArtifact || testMethods.empty()) {
259+
return;
260+
}
261+
262+
for (const auto &testMethod : testMethods) {
263+
if (testMethod.sourceFilePath != tests.sourceFilePath) {
264+
std::string message = StringUtils::stringFormat(
265+
"While generating tests for source file: %s tried to generate tests for method %s "
266+
"from another source file: %s. This can cause invalid generation.\n",
267+
tests.sourceFilePath, testMethod.methodName, testMethod.sourceFilePath);
268+
LOG_S(WARNING) << message;
269+
}
270+
271+
auto [argvData, kleeOut] = createKleeParams(testMethod, tests, testMethod.methodName);
272+
addTailKleeInitParams(argvData, testMethod.bitcodeFilePath);
273+
{
274+
std::vector<char *> cargv, cenvp;
275+
std::vector<std::string> tmp;
276+
ExecUtils::toCArgumentsPtr(argvData, tmp, cargv, cenvp, false);
277+
LOG_S(DEBUG) << "Klee command :: " + StringUtils::joinWith(argvData, " ");
278+
MEASURE_FUNCTION_EXECUTION_TIME
262279

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

291-
TestMethod testMethod = testMethods[0];
292-
std::string entryPoint = KleeUtils::entryPointFunction(tests, testMethod.methodName, true);
293-
std::string entryPointFlag = StringUtils::stringFormat("--entry-point=%s", entryPoint);
294-
auto kleeOut = Paths::kleeOutDirForEntrypoints(projectContext, projectTmpPath, tests.sourceFilePath);
295-
fs::create_directories(kleeOut.parent_path());
296-
297-
fs::path entrypoints = kleeOut.parent_path() / "entrypoints.txt";
298-
std::ofstream of(entrypoints);
299-
for (const auto &method : testMethods) {
300-
of << KleeUtils::entryPointFunction(tests, method.methodName, true) << std::endl;
301-
}
302-
of.close();
303-
std::string entrypointsArg = "--entrypoints-file=" + entrypoints.string();
304-
305-
std::string outputDir = "--output-dir=" + kleeOut.string();
306-
std::vector<std::string> argvData = { "klee",
307-
entryPointFlag,
308-
"--libc=klee",
309-
"--utbot",
310-
"--posix-runtime",
311-
"--fp-runtime",
312-
"--only-output-states-covering-new",
313-
"--allocate-determ",
314-
"--external-calls=all",
315-
"--timer-interval=1000ms",
316-
"--bcov-check-interval=6s",
317-
"-istats-write-interval=5s",
318-
"--disable-verify",
319-
"--check-div-zero=false",
320-
"--check-overshift=false",
321-
"--skip-not-lazy-and-symbolic-pointers",
322-
"--interactive",
323-
KleeUtils::processNumberOption(),
324-
entrypointsArg,
325-
outputDir };
326-
if (settingsContext.timeoutPerFunction.has_value()) {
327-
argvData.push_back(StringUtils::stringFormat("--timeout-per-function=%d", settingsContext.timeoutPerFunction.value()));
328-
}
329-
if (settingsContext.useDeterministicSearcher) {
330-
argvData.emplace_back("--search=dfs");
308+
auto [argvData, kleeOut] = createKleeParams(testMethods[0], tests, "");
309+
{
310+
// additional KLEE arguments
311+
argvData.emplace_back("--interactive");
312+
argvData.emplace_back(KleeUtils::processNumberOption());
313+
{
314+
// entrypoints
315+
fs::path entrypoints = kleeOut.parent_path() / "entrypoints.txt";
316+
std::ofstream of(entrypoints);
317+
for (const auto &method : testMethods) {
318+
of << KleeUtils::entryPointFunction(tests, method.methodName, true) << std::endl;
319+
}
320+
argvData.emplace_back("--entrypoints-file=" + entrypoints.string());
321+
}
322+
if (settingsContext.timeoutPerFunction.has_value()) {
323+
argvData.emplace_back(StringUtils::stringFormat(
324+
"--timeout-per-function=%d", settingsContext.timeoutPerFunction.value()));
325+
}
326+
addTailKleeInitParams(argvData, testMethods[0].bitcodeFilePath);
331327
}
332-
argvData.push_back(testMethod.bitcodeFilePath);
333-
argvData.emplace_back("--sym-stdin");
334-
argvData.emplace_back(std::to_string(types::Type::symStdinSize));
335-
336328
{
337329
std::vector<char *> cargv, cenvp;
338330
std::vector<std::string> tmp;

server/src/KleeRunner.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ class KleeRunner {
4848
void processBatchWithInteractive(const std::vector<tests::TestMethod> &testMethods,
4949
tests::Tests &tests,
5050
std::vector<tests::MethodKtests> &ktests);
51+
52+
std::pair<std::vector<std::string>, fs::path>
53+
createKleeParams(const tests::TestMethod &testMethod,
54+
const tests::Tests &tests,
55+
const std::string &methodNameOrEmptyForFolder);
56+
57+
void addTailKleeInitParams(std::vector<std::string> &argvData,
58+
const std::string &bitcodeFilePath);
5159
};
5260

5361

server/src/Paths.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,14 @@ namespace Paths {
168168
return kleeOutDir / relative;
169169
}
170170

171-
fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext, const fs::path &projectTmpPath,
172-
const fs::path &srcFilePath, const std::string &methodName) {
171+
fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext,
172+
const fs::path &projectTmpPath,
173+
const fs::path &srcFilePath,
174+
const std::string &methodNameOrEmptyForFolder) {
173175
auto kleeOutDirForFile = kleeOutDirForFilePath(projectContext, projectTmpPath, srcFilePath);
174-
std::string suffix = methodName.empty() ?
175-
addOrigExtensionAsSuffixAndAddNew(srcFilePath, "").filename().string() : methodName;
176+
std::string suffix = methodNameOrEmptyForFolder.empty()
177+
? addOrigExtensionAsSuffixAndAddNew(srcFilePath, "").filename().string()
178+
: methodNameOrEmptyForFolder;
176179
return kleeOutDirForFile / ("klee_out_" + suffix);
177180
}
178181

server/src/Paths.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,10 @@ namespace Paths {
242242
fs::path kleeOutDirForFilePath(const utbot::ProjectContext &projectContext, const fs::path &projectTmpPath,
243243
const fs::path &filePath);
244244

245-
fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext, const fs::path &projectTmpPath,
246-
const fs::path &srcFilePath, const std::string &methodName = "");
245+
fs::path kleeOutDirForEntrypoints(const utbot::ProjectContext &projectContext,
246+
const fs::path &projectTmpPath,
247+
const fs::path &srcFilePath,
248+
const std::string &methodNameOrEmptyForFolder);
247249

248250
//endregion
249251

server/src/SARIFGenerator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ namespace sarif {
7676
const fs::path &srcPath = fs::path(stack_match[3]);
7777
const fs::path &relPathInProject = getInProjectPath(projectContext.projectPath, srcPath);
7878
const fs::path &fullPathInProject = projectContext.projectPath / relPathInProject;
79-
if (Paths::isSubPathOf(projectContext.buildDir(), fullPathInProject)) {
80-
LOG_S(DEBUG) << "Full path " << fullPathInProject << " is in build - skip it";
79+
if (Paths::isSubPathOf(Paths::getUtbotBuildDir(projectContext), fullPathInProject)) {
80+
LOG_S(WARNING) << "Full path " << fullPathInProject << " is in build - skip it";
8181
continue;
8282
}
8383
if (!relPathInProject.empty() && fs::exists(fullPathInProject)) {

server/src/Tests.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,13 +1137,16 @@ UnionValueView::UnionValueView(
11371137
entryValue(PrinterUtils::convertBytesToUnion(typeName, rawDataView->getEntryValue(nullptr))) {
11381138
}
11391139

1140-
TestMethod::TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename)
1141-
: methodName(std::move(methodName)), bitcodeFilePath(std::move(bitcodeFile)),
1142-
sourceFilePath(std::move(sourceFilename)) {
1143-
}
1140+
TestMethod::TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename, bool is32)
1141+
: methodName(std::move(methodName))
1142+
, bitcodeFilePath(std::move(bitcodeFile))
1143+
, sourceFilePath(std::move(sourceFilename))
1144+
, is32bits(is32)
1145+
{}
11441146

11451147
bool TestMethod::operator==(const TestMethod &rhs) const {
1146-
return std::tie(methodName, bitcodeFilePath, sourceFilePath) == std::tie(rhs.methodName, rhs.bitcodeFilePath, rhs.sourceFilePath);
1148+
return std::tie( methodName, bitcodeFilePath, sourceFilePath, is32bits)
1149+
== std::tie(rhs.methodName, rhs.bitcodeFilePath, rhs.sourceFilePath, rhs.is32bits);
11471150
}
11481151
bool TestMethod::operator!=(const TestMethod &rhs) const {
11491152
return !(rhs == *this);

server/src/Tests.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,10 +557,12 @@ namespace tests {
557557
std::string methodName;
558558
fs::path bitcodeFilePath;
559559
fs::path sourceFilePath;
560+
bool is32bits;
561+
560562
bool operator==(const TestMethod &rhs) const;
561563
bool operator!=(const TestMethod &rhs) const;
562564

563-
TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename);
565+
TestMethod(std::string methodName, fs::path bitcodeFile, fs::path sourceFilename, bool is32);
564566
};
565567

566568
using MethodKtests = std::unordered_map<TestMethod, UTBotKTestList, HashUtils::TestMethodHash>;

server/src/building/BuildDatabase.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,10 @@ void BuildDatabase::ObjectFileInfo::addFile(fs::path file) {
567567
files.insert(std::move(file));
568568
}
569569

570+
bool BuildDatabase::ObjectFileInfo::is32bits() const {
571+
return CollectionUtils::contains(command.getCommandLine(), "-m32");
572+
}
573+
570574
void BuildDatabase::TargetInfo::addFile(fs::path file) {
571575
files.insert(std::move(file));
572576
}

0 commit comments

Comments
 (0)