From a37f6c53c396e285d6003436461795613ea55b5f Mon Sep 17 00:00:00 2001 From: IDKWNTCMF Date: Tue, 8 Aug 2023 16:40:33 +0300 Subject: [PATCH 1/2] Alter variable wrappers generation and usage --- .../SourceToHeaderMatchCallback.cpp | 35 ++++++++++++++----- .../clang-utils/SourceToHeaderMatchCallback.h | 4 +++ server/src/utils/PrinterUtils.cpp | 18 ++++++++++ server/src/utils/PrinterUtils.h | 8 +++++ 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/server/src/clang-utils/SourceToHeaderMatchCallback.cpp b/server/src/clang-utils/SourceToHeaderMatchCallback.cpp index 3256f1112..62f06752d 100644 --- a/server/src/clang-utils/SourceToHeaderMatchCallback.cpp +++ b/server/src/clang-utils/SourceToHeaderMatchCallback.cpp @@ -236,8 +236,8 @@ void SourceToHeaderMatchCallback::generateInternal(const VarDecl *decl) const { policy.SuppressInitializers = 1; /* - * extern "C" (*var_wrapper); - * &DECL = *var_wrapper; + * extern "C" (*get_var_wrapper); + * &DECL = *get_var_wrapper(); */ std::string name = decl->getNameAsString(); @@ -252,9 +252,13 @@ void SourceToHeaderMatchCallback::generateInternal(const VarDecl *decl) const { std::string wrapperPointerDecl = getRenamedDeclarationAsString(decl, policy, wrapperPointerName); std::string refDecl = getRenamedDeclarationAsString(decl, policy, refName); + PrinterUtils::removeThreadLocalQualifiers(refDecl); - *internalStream << "extern \"C\" " << wrapperPointerDecl << ";\n"; - *internalStream << refDecl << " = " << wrapperPointerName << ";\n"; + std::string returnTypeName = PrinterUtils::getPointerMangledName(name); + std::string getterName = PrinterUtils::getterName(wrapperName); + *internalStream << generateTypedefForGetterReturnType(decl, policy, returnTypeName); + *internalStream << "extern \"C\" " << PrinterUtils::getterDecl(returnTypeName, wrapperName) << ";\n"; + *internalStream << stringFormat("%s = *%s();\n", refDecl, getterName); } void SourceToHeaderMatchCallback::generateWrapper(const FunctionDecl *decl) const { @@ -295,15 +299,18 @@ void SourceToHeaderMatchCallback::generateWrapper(const VarDecl *decl) const { policy.SuppressInitializers = 1; /* - * (*var_wrapper) = &var; + * get_var_wrapper { + * return &var; + * } */ std::string name = decl->getNameAsString(); std::string wrapperName = PrinterUtils::wrapperName(name, projectContext, sourceFilePath); - std::string wrapperPointerName = stringFormat("(*%s)", wrapperName); - std::string wrapperPointerDecl = - getRenamedDeclarationAsString(decl, policy, wrapperPointerName); - *wrapperStream << wrapperPointerDecl << " = &" << name << ";\n"; + std::string returnTypeName = PrinterUtils::getPointerMangledName(name); + *wrapperStream << generateTypedefForGetterReturnType(decl, policy, returnTypeName); + *wrapperStream << PrinterUtils::getterDecl(returnTypeName, wrapperName) << " {\n"; + *wrapperStream << stringFormat("return &%s;\n", name); + *wrapperStream << "}\n"; } void SourceToHeaderMatchCallback::generateUnnamedTypeDecls(const clang::RecordDecl *decl) const { @@ -411,6 +418,16 @@ SourceToHeaderMatchCallback::getDefaultPrintingPolicy(const Decl *decl, return policy; } +std::string +SourceToHeaderMatchCallback::generateTypedefForGetterReturnType(const clang::VarDecl *decl, + const clang::PrintingPolicy &policy, + const std::string &returnTypeName) const { + std::string wrapperPointerName = stringFormat("(*%s)", returnTypeName); + std::string wrapperPointerDecl = getRenamedDeclarationAsString(decl, policy, wrapperPointerName); + PrinterUtils::removeThreadLocalQualifiers(wrapperPointerDecl); + return "typedef " + wrapperPointerDecl + ";\n"; +} + std::string SourceToHeaderMatchCallback::getRenamedDeclarationAsString(const clang::NamedDecl *decl, clang::PrintingPolicy const &policy, diff --git a/server/src/clang-utils/SourceToHeaderMatchCallback.h b/server/src/clang-utils/SourceToHeaderMatchCallback.h index 4f082f111..961826184 100644 --- a/server/src/clang-utils/SourceToHeaderMatchCallback.h +++ b/server/src/clang-utils/SourceToHeaderMatchCallback.h @@ -93,6 +93,10 @@ class SourceToHeaderMatchCallback : public clang::ast_matchers::MatchFinder::Mat void generateUnnamedTypeDecls(const clang::RecordDecl *decl) const; + std::string generateTypedefForGetterReturnType(const clang::VarDecl *decl, + const clang::PrintingPolicy &policy, + const std::string &returnTypeName) const; + std::string getRenamedDeclarationAsString(const clang::NamedDecl *decl, clang::PrintingPolicy const &policy, std::string const &name) const; diff --git a/server/src/utils/PrinterUtils.cpp b/server/src/utils/PrinterUtils.cpp index 45692f0b8..031b140e2 100644 --- a/server/src/utils/PrinterUtils.cpp +++ b/server/src/utils/PrinterUtils.cpp @@ -22,6 +22,16 @@ namespace PrinterUtils { return StringUtils::stringFormat("%s_%s", declName, mangledPath); } + std::string getterName(const std::string &wrapperName) { + return "get_" + wrapperName; + } + + std::string getterDecl(const std::string &returnTypeName, + const std::string &wrapperName) { + std::string gName = getterName(wrapperName); + return StringUtils::stringFormat("%s %s()", returnTypeName, gName); + } + std::string getFieldAccess(const std::string &objectName, const types::Field &field) { if (field.name.empty()) { return objectName; @@ -89,6 +99,10 @@ namespace PrinterUtils { } } + std::string getPointerMangledName(const std::string &name) { + return name + "_pointer"; + } + std::string getParamMangledName(const std::string& paramName, const std::string& methodName) { return methodName + "_" + paramName + "_arg"; } @@ -128,4 +142,8 @@ namespace PrinterUtils { std::string getFileWriteBytesParamKTestJSON(char fileName) { return StringUtils::stringFormat("%c-data-write", fileName); } + + void removeThreadLocalQualifiers(std::string &decl) { + StringUtils::replaceAll(decl, "__thread ", ""); + } } diff --git a/server/src/utils/PrinterUtils.h b/server/src/utils/PrinterUtils.h index b61e1e4a1..afca6328f 100644 --- a/server/src/utils/PrinterUtils.h +++ b/server/src/utils/PrinterUtils.h @@ -68,6 +68,11 @@ namespace PrinterUtils { utbot::ProjectContext const &projectContext, const fs::path &sourceFilePath); + std::string getterName(const std::string &wrapperName); + + std::string getterDecl(const std::string &returnTypeName, + const std::string &wrapperName); + std::string getFieldAccess(const std::string &objectName, const types::Field &field); std::string fillVarName(std::string const &temp, std::string const &varName); @@ -76,6 +81,7 @@ namespace PrinterUtils { std::string wrapUserValue(const testsgen::ValidationType &type, const std::string &value); + std::string getPointerMangledName(const std::string &name); std::string getParamMangledName(const std::string ¶mName, const std::string &methodName); std::string getReturnMangledName(const std::string &methodName); std::string getReturnMangledTypeName(const std::string& methodName); @@ -99,6 +105,8 @@ namespace PrinterUtils { std::string getFileReadBytesParamKTestJSON(char fileName); std::string getFileWriteBytesParamKTestJSON(char fileName); + void removeThreadLocalQualifiers(std::string &decl); + const std::string LAZYRENAME = "utbotInnerVar"; const std::string UTBOT_ARGC = "utbot_argc"; const std::string UTBOT_ARGV = "utbot_argv"; From 123f096c04764c09664129cbcfd0727b7babb165 Mon Sep 17 00:00:00 2001 From: IDKWNTCMF Date: Tue, 8 Aug 2023 16:58:10 +0300 Subject: [PATCH 2/2] Add tests for this case --- server/test/framework/Server_Tests.cpp | 38 ++++++++++++++++++++++++ server/test/suites/server/CMakeLists.txt | 1 + server/test/suites/server/thread_local.c | 19 ++++++++++++ server/test/suites/server/thread_local.h | 12 ++++++++ 4 files changed, 70 insertions(+) create mode 100644 server/test/suites/server/thread_local.c create mode 100644 server/test/suites/server/thread_local.h diff --git a/server/test/framework/Server_Tests.cpp b/server/test/framework/Server_Tests.cpp index d24d86e61..5a419f316 100644 --- a/server/test/framework/Server_Tests.cpp +++ b/server/test/framework/Server_Tests.cpp @@ -2179,4 +2179,42 @@ namespace { StatusCountMap expectedStatusCountMap{ { testsgen::TEST_PASSED, 3 } }; testUtils::checkStatuses(resultsMap, tests); } + + TEST_F(Server_Test, Run_Tests_For_Thread_Local) { + fs::path thread_local_c = getTestFilePath("thread_local.c"); + auto request = testUtils::createFileRequest(projectName, suitePath, buildDirRelativePath, + srcPaths, thread_local_c, + GrpcUtils::UTBOT_AUTO_TARGET_PATH, true, false); + auto testGen = FileTestGen(*request, writer.get(), TESTMODE); + Status status = Server::TestsGenServiceImpl::ProcessBaseTestRequest(testGen, writer.get()); + ASSERT_TRUE(status.ok()) << status.error_message(); + EXPECT_GE(testUtils::getNumberOfTests(testGen.tests), 3); + + fs::path testsDirPath = getTestFilePath("tests"); + + fs::path thread_local_test_cpp = Paths::sourcePathToTestPath( + utbot::ProjectContext(projectName, suitePath, testsDirPath, buildDirRelativePath, clientProjectPath), + thread_local_c); + auto testFilter = GrpcUtils::createTestFilterForFile(thread_local_test_cpp); + auto runRequest = testUtils::createCoverageAndResultsRequest( + projectName, suitePath, testsDirPath, buildDirRelativePath, std::move(testFilter)); + + static auto coverageAndResultsWriter = + std::make_unique(nullptr); + CoverageAndResultsGenerator coverageGenerator{ runRequest.get(), + coverageAndResultsWriter.get() }; + utbot::SettingsContext settingsContext{ + true, false, 45, 0, false, false, ErrorMode::FAILING, false + }; + coverageGenerator.generate(false, settingsContext); + + EXPECT_FALSE(coverageGenerator.hasExceptions()); + ASSERT_TRUE(coverageGenerator.getCoverageMap().empty()); + + auto resultsMap = coverageGenerator.getTestResultMap(); + auto tests = coverageGenerator.getTestsToLaunch(); + + StatusCountMap expectedStatusCountMap{ { testsgen::TEST_PASSED, 3 } }; + testUtils::checkStatuses(resultsMap, tests); + } } diff --git a/server/test/suites/server/CMakeLists.txt b/server/test/suites/server/CMakeLists.txt index 0c0502edf..1939be86c 100644 --- a/server/test/suites/server/CMakeLists.txt +++ b/server/test/suites/server/CMakeLists.txt @@ -26,6 +26,7 @@ add_executable(server simple_unions.c struct_with_union.c structs_with_pointers.c + thread_local.c complex_structs.c typedefs.c types.c diff --git a/server/test/suites/server/thread_local.c b/server/test/suites/server/thread_local.c new file mode 100644 index 000000000..8281724d0 --- /dev/null +++ b/server/test/suites/server/thread_local.c @@ -0,0 +1,19 @@ +#include "thread_local.h" + +__thread int thread_local_id; + +void set_id(int id) { + thread_local_id = id + 5; +} + +__thread char thread_local_bytes[8]; +void set_bytes(char bytes[8]) { + for (int i = 0; i < 8; ++i) { + thread_local_bytes[i] = bytes[7 - i]; + } +} + +__thread struct ThreadLocalStorage thread_local_storage; +void set_storage(struct ThreadLocalStorage storage) { + thread_local_storage.fld = - storage.fld - 10; +} \ No newline at end of file diff --git a/server/test/suites/server/thread_local.h b/server/test/suites/server/thread_local.h new file mode 100644 index 000000000..24c9614ea --- /dev/null +++ b/server/test/suites/server/thread_local.h @@ -0,0 +1,12 @@ +#ifndef UNITTESTBOT_THREAD_LOCAL_H +#define UNITTESTBOT_THREAD_LOCAL_H + +struct ThreadLocalStorage { + int fld; +}; + +void set_id(int id); + +void set_bytes(char bytes[8]); + +#endif // UNITTESTBOT_THREAD_LOCAL_H