Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
50 changes: 50 additions & 0 deletions integration-tests/c-example/lib/linked-list/linked-list.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,54 @@ int sort_list(struct Node *head) {
}
}
return 0;
}

int sort_list_with_comparator(struct Node *head, int (*cmp) (int, int)) {
int n = len_bound(head, SIZE);
if (n == SIZE) {
for (int i = 0; i < n - 2; i++) {
struct Node *cop = head;
while (cop->next != NULL) {
if (!cmp(cop->x, cop->next->x)) {
int t = cop->x;
cop->x = cop->next->x;
cop->next->x = t;
}
cop = cop->next;
}
}
int fl = 1;
struct Node *cop = head;
while (cop->next != NULL) {
if (!cmp(cop->x, cop->next->x)) {
fl = -1;
}
cop = cop->next;
}
if (fl == 1) {
return 1;
} else {
return -1;
}
}
return 0;
}

int find_maximum(int x, int y, int (*compare) (int, int)) {
int t = compare(x, y);
if (t) {
return x;
} else {
return y;
}
}

int vowel_consonant(char c, char (*vowel) (char)) {
char s = vowel(c);
if (s == 'a' || s == 'e' || s == 'i' || s == 'o' || s == 'u' || s == 'y') {
return 1;
} else {
return -1;
}

}
6 changes: 6 additions & 0 deletions integration-tests/c-example/lib/linked-list/linked-list.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,10 @@ int len_bound(struct Node *head, int bound);

int sort_list(struct Node *head);

int sort_list_with_comparator(struct Node *head, int (*cmp) (int, int));

int find_maximum(int x, int y, int (*compare) (int, int));

int vowel_consonant(char c, char (*vowel) (char));

#endif
Empty file modified server/build.sh
100644 → 100755
Empty file.
21 changes: 21 additions & 0 deletions server/src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,26 @@ void KTestObjectParser::assignTypeUnnamedVar(Tests::MethodTestCase &testCase,
}
}

void KTestObjectParser::assignTypeStubVar(Tests::MethodTestCase &testCase,
const Tests::MethodDescription &methodDescription) {
for (auto const &obj : testCase.objects) {
if (StringUtils::endsWith(obj.name, PrinterUtils::KLEE_SYMBOLIC_SUFFIX)) {
std::string stubFuncName = obj.name.substr(0, obj.name.length() - PrinterUtils::KLEE_SYMBOLIC_SUFFIX.length());
if (!CollectionUtils::contains(methodDescription.functionPointers, stubFuncName)) {
std::string message = "Can't find function pointer with name " + stubFuncName;
LOG_S(ERROR) << message;
continue;
}
types::Type stubType = types::Type::createArray(methodDescription.functionPointers.at(stubFuncName)->returnType);
shared_ptr<AbstractValueView> stubView = testParameterView({obj.name, obj.bytes}, {stubType, obj.name},
PointerUsage::PARAMETER, testCase.fromAddressToName,
testCase.lazyReferences, methodDescription);
testCase.stubParamValues.emplace_back(obj.name, 0, stubView);
testCase.stubParamTypes.emplace_back(stubType, obj.name, std::nullopt);
}
}
}

void KTestObjectParser::parseTestCases(const UTBotKTestList &cases,
bool filterByLineFlag,
Tests::MethodDescription &methodDescription,
Expand Down Expand Up @@ -709,6 +729,7 @@ void KTestObjectParser::parseTestCases(const UTBotKTestList &cases,
LOG_S(MAX) << traceStream.str();

assignTypeUnnamedVar(testCase, methodDescription);
assignTypeStubVar(testCase, methodDescription);

methodDescription.testCases.push_back(testCase);
}
Expand Down
8 changes: 7 additions & 1 deletion server/src/Tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ namespace tests {
const shared_ptr<AbstractValueView> &view)
: name(std::move(name)), alignment(alignment), view(view) {};
};

struct TestCaseDescription {
string scopeName;

Expand Down Expand Up @@ -374,6 +375,8 @@ namespace tests {
vector<TestCaseParamValue> paramValues;
vector<TestCaseParamValue> paramPostValues;
vector<TestCaseParamValue> lazyValues;
vector<TestCaseParamValue> stubParamValues;
vector<MethodParam> stubParamTypes;
shared_ptr<AbstractValueView> returnValueView;

bool isError() const;
Expand Down Expand Up @@ -665,7 +668,10 @@ namespace tests {
vector<RawKleeParam> &rawKleeParams);

void assignTypeUnnamedVar(Tests::MethodTestCase &testCase,
const Tests::MethodDescription &methodDescription);
const Tests::MethodDescription &methodDescription);

void assignTypeStubVar(Tests::MethodTestCase &testCase,
const Tests::MethodDescription &methodDescription);

void workWithStructInBFS(std::queue<JsonNumAndType> &order, std::vector<bool> &visited,
const Offset &off, std::vector<UTBotKTestObject> &objects, const types::StructInfo &structInfo);
Expand Down
64 changes: 44 additions & 20 deletions server/src/printers/Printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "utils/ArgumentsUtils.h"
#include "utils/Copyright.h"
#include "visitors/VerboseParameterVisitor.h"
#include "printers/KleeConstraintsPrinter.h"

#include "loguru.h"

Expand Down Expand Up @@ -385,15 +386,30 @@ namespace printer {
return ss;
}

std::stringstream& Printer::checkOverflowStubArray(const string &cntCall) {
ss << TAB_N() << "if (" << cntCall << " == " <<
types::TypesHandler::getElementsNumberInPointerOneDim(types::PointerUsage::PARAMETER) << ") {" << NL;
tabsDepth++;
ss << TAB_N() << cntCall << "--;" << NL;
ss << RB();
return ss;
}


std::stringstream &Printer::strStubForMethod(const Tests::MethodDescription &method,
const types::TypesHandler &typesHandler,
const string &prefix,
const string &suffix,
bool makeSymbolic,
bool makeStatic) {
auto methodCopy = method;

methodCopy.name = method.name;

string stubSymbolicVarName = getStubSymbolicVarName(method.name);
if (!types::TypesHandler::isVoid(method.returnType)) {
strDeclareArrayVar(types::Type::createArray(method.returnType), stubSymbolicVarName,
types::PointerUsage::PARAMETER);
}

if (!prefix.empty()) {
methodCopy.name = prefix + "_" + methodCopy.name;
}
Expand All @@ -411,23 +427,31 @@ namespace printer {
strReturn(returnValue) << RB() << NL;
return ss;
}
if (makeSymbolic) {
string firstTimeCallVar = "firstTimeCall";
string stubSymbolicVarName = getStubSymbolicVarName(method.name);
strDeclareVar("static int", firstTimeCallVar, "1");
ss << TAB_N() << "#ifdef " << PrinterUtils::KLEE_MODE << NL;
tabsDepth++;
ss << TAB_N() << "if (" << firstTimeCallVar << " == 1)" << LB();
strAssignVar(firstTimeCallVar, "0");
strKleeMakeSymbolic(stubSymbolicVarName, !method.returnType.isArray(),
stubSymbolicVarName);
ss << RB();
tabsDepth--;
ss << TAB_N() << "#endif" << NL;
returnValue = stubSymbolicVarName;
} else {
returnValue = typesHandler.getDefaultValueForType(methodCopy.returnType, getLanguage());
}

string firstTimeCallVar = "firstTimeCall";
strDeclareVar("static int", firstTimeCallVar, "1");
const string cntCall = "cntCall";
strDeclareVar("static int", cntCall, "0");
ss << TAB_N() << "#ifdef " << PrinterUtils::KLEE_MODE << NL;
tabsDepth++;
ss << TAB_N() << "if (" << firstTimeCallVar << " == 1)" << LB();
strAssignVar(firstTimeCallVar, "0");
strKleeMakeSymbolic(stubSymbolicVarName, !method.returnType.isArray(),
stubSymbolicVarName);
types::TypeMaps tempMap = {};
auto temp = shared_ptr <types::TypesHandler>(new types::TypesHandler(tempMap, types::TypesHandler::SizeContext()));
printer::KleeConstraintsPrinter preferWriter(temp.get(), srcLanguage);
preferWriter.setTabsDepth(tabsDepth);
preferWriter.genConstraints(
{types::Type::createArray(method.returnType), stubSymbolicVarName, std::nullopt});
ss << preferWriter.ss.str();
ss << RB();
tabsDepth--;
ss << TAB_N() << "#endif" << NL;

checkOverflowStubArray(cntCall);

returnValue = stubSymbolicVarName + "[" + cntCall + "++]";
strReturn(returnValue) << RB() << NL;
return ss;
}
Expand Down Expand Up @@ -552,7 +576,7 @@ namespace printer {
strTypedefFunctionPointer(*fInfo, typedefName);
}
strStubForMethod(tests::Tests::MethodDescription::fromFunctionInfo(*fInfo), *typesHandler,
stubName, "stub", false, makeStatic);
stubName, "stub", makeStatic);
}

void Printer::genStubForStructFunctionPointer(const string &structName,
Expand Down
5 changes: 3 additions & 2 deletions server/src/printers/Printer.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ namespace printer {

Stream strAssignVar(std::string_view name, std::string_view value);

std::stringstream& checkOverflowStubArray(const string &cntCall);

Stream strTabIf(bool needTabs);

Stream strFunctionDecl(
Expand Down Expand Up @@ -178,7 +180,6 @@ namespace printer {

Stream strReturn(std::string_view value);


Stream strTypedefFunctionPointer(const types::FunctionInfo& method, const string& name);

Stream strDeclareArrayOfFunctionPointerVar(const string&arrayType, const string& arrayName,
Expand All @@ -187,7 +188,7 @@ namespace printer {
Stream strStubForMethod(const Tests::MethodDescription& method,
const types::TypesHandler&typesHandler,
const string& prefix,
const string& suffix, bool makeSymbolic = false,
const string& suffix,
bool makeStatic = false);

static string getStubSymbolicVarName(const string& methodName);
Expand Down
8 changes: 2 additions & 6 deletions server/src/printers/StubsPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,12 @@ Stubs printer::StubsPrinter::genStubFile(const tests::Tests &tests,
param.type = copyParamType;
}
}
if (!typesHandler.omitMakeSymbolic(methodCopy.returnType)) {
string symbolicVarName = Printer::getStubSymbolicVarName(methodCopy.name);
strDeclareVar(methodCopy.returnType.usedType(), symbolicVarName, std::nullopt, std::nullopt,
true, 0);
}

if (methodCopy.sourceBody) {
strFunctionDecl(methodCopy, " ");
ss << methodCopy.sourceBody.value() << NL;
} else {
strStubForMethod(methodCopy, typesHandler, "", "", true);
strStubForMethod(methodCopy, typesHandler, "", "");
};
ss << NL;
}
Expand Down
13 changes: 13 additions & 0 deletions server/src/printers/TestsPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ void TestsPrinter::printLazyReferences(const Tests::MethodDescription &methodDes
}
}

void TestsPrinter::printStubVariables(const Tests::MethodDescription &methodDescription,
const Tests::MethodTestCase &testCase) {
for (int i = 0; i < testCase.stubParamValues.size(); i++) {
auto stub = testCase.stubParamValues[i];
types::Type stubType = testCase.stubParamTypes[i].type;
std::string bufferSuffix = "_buffer";
std::string buffer = stub.name + bufferSuffix;
strDeclareArrayVar(stubType, buffer, types::PointerUsage::PARAMETER, stub.view->getEntryValue());
strMemcpy(stub.name, buffer, false);
}
}

void TestsPrinter::genParametrizedTestCase(const Tests::MethodDescription &methodDescription,
const Tests::MethodTestCase &testCase,
const std::optional<LineInfo::PredicateInfo>& predicateInfo) {
Expand All @@ -145,6 +157,7 @@ void TestsPrinter::genParametrizedTestCase(const Tests::MethodDescription &metho
printClassObject(methodDescription);
printLazyVariables(methodDescription, testCase);
printLazyReferences(methodDescription, testCase);
printStubVariables(methodDescription, testCase);
printFunctionParameters(methodDescription, testCase, true);
parametrizedAsserts(methodDescription, testCase, predicateInfo);
ss << RB() << NL;
Expand Down
3 changes: 3 additions & 0 deletions server/src/printers/TestsPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ namespace printer {
void printLazyReferences(const Tests::MethodDescription &methodDescription,
const Tests::MethodTestCase &testCase);

void printStubVariables(const Tests::MethodDescription &methodDescription,
const Tests::MethodTestCase &testCase);

static Tests::MethodParam getValueParam(const Tests::MethodParam &param);
};
}
Expand Down
15 changes: 15 additions & 0 deletions server/src/types/Types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ types::Type types::Type::createConstTypeFromName(const types::TypeName& type, si
return res;
}

types::Type types::Type::createArray(const types::Type &type) {
Type res;
res.mType = type.typeName() + "*";
res.mUsedType = res.mType;
res.mBaseType = type.baseType();
res.mKinds = type.mKinds;
res.mKinds.insert(res.mKinds.begin(), std::shared_ptr<AbstractType>(new ArrayType(
TypesHandler::getElementsNumberInPointerOneDim(PointerUsage::PARAMETER), false)));
res.dimension = type.dimension + 1;
res.mTypeId = 0;
res.mBaseTypeId = type.mBaseTypeId;
res.maybeArray = true;
return res;
}

types::TypeName types::Type::typeName() const {
return mType;
}
Expand Down
4 changes: 3 additions & 1 deletion server/src/types/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ namespace types {
*/
static Type createConstTypeFromName(const TypeName &type, size_t pointersNum=0);

static Type createArray(const Type &type);

static Type CStringType();

static Type intType();
Expand All @@ -241,7 +243,7 @@ namespace types {
static const std::string &getStdinParamName();
private:

explicit Type(const TypeName& type, size_t pointersNum=0);
explicit Type(const TypeName& type, size_t pointersNum=0);

TypeName mType;
TypeName mBaseType;
Expand Down
38 changes: 38 additions & 0 deletions server/test/framework/Syntax_Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1818,6 +1818,44 @@ namespace {
);
}

TEST_F(Syntax_Test, sort_list_with_cmp) {
auto [testGen, status] = createTestForFunction(linked_list_c, 135);

ASSERT_TRUE(status.ok()) << status.error_message();

checkTestCasePredicates(
testGen.tests.at(linked_list_c).methods.begin().value().testCases,
vector<TestCasePredicate>(
{
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValueView->getEntryValue()) == -1;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValueView->getEntryValue()) == 1;
},
[] (const tests::Tests::MethodTestCase& testCase) {
return stoi(testCase.returnValueView->getEntryValue()) == 0;
}
})
);
}

TEST_F(Syntax_Test, find_maximum) {
auto [testGen, status] = createTestForFunction(linked_list_c, 166);

ASSERT_TRUE(status.ok()) << status.error_message();

EXPECT_EQ(2, testUtils::getNumberOfTests(testGen.tests));
}

TEST_F(Syntax_Test, vowel_consonant) {
auto [testGen, status] = createTestForFunction(linked_list_c, 175);

ASSERT_TRUE(status.ok()) << status.error_message();

EXPECT_TRUE(testUtils::getNumberOfTests(testGen.tests) >= 2);
}

TEST_F(Syntax_Test, tree_deep) {
auto [testGen, status] = createTestForFunction(tree_c, 3, 45);

Expand Down
Loading