From 328b12abc9ffb195f47d3595cc0d3adfcf9b480f Mon Sep 17 00:00:00 2001 From: fancy <258828110.@qq.com> Date: Sun, 28 Jan 2024 06:08:47 -0800 Subject: [PATCH] Improve:Optimize multi-threaded security vulnerabilities in test code. --- test/CMakeLists.txt | 2 +- .../utils/LinuxApiMock/include/LinuxApiMock.h | 43 +++++++++- test/utils/LinuxApiMock/src/LinuxApiMock.cpp | 2 +- test/utils/LinuxApiMock/src/LinuxTestImpl.cpp | 80 ++++++++++++++++--- test/utils/LinuxApiMock/src/LinuxTestImpl.h | 20 +++++ test/utils/LinuxApiMock/src/WrapApi.cpp | 18 +++++ test/utils/LinuxApiMock/src/WrapApi.h | 2 + .../src_mock/UartDevice_Mock_Test.cpp | 31 ++++++- utils/LinuxApi/include/LinuxApi.h | 3 + utils/LinuxApi/src/LinuxApi.c | 9 ++- utils/UartDevice/src/UartDeviceImpl.cpp | 1 + 11 files changed, 192 insertions(+), 19 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fb2e446c..72163610 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,7 +18,7 @@ if(${TARGET_PLATFORM} MATCHES ${DEFINE_LINUX}) # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=select" CACHE STRING INTERNAL FORCE) # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=linux_open" CACHE STRING INTERNAL FORCE) # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=linux_read" CACHE STRING INTERNAL FORCE) - # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=linux_write" CACHE STRING INTERNAL FORCE) + set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=fx_write" CACHE STRING INTERNAL FORCE) # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=linux_close" CACHE STRING INTERNAL FORCE) # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=linux_fclose" CACHE STRING INTERNAL FORCE) # set(TEST_LINUX_MOCK "${TEST_LINUX_MOCK},--wrap=linux_fread" CACHE STRING INTERNAL FORCE) diff --git a/test/utils/LinuxApiMock/include/LinuxApiMock.h b/test/utils/LinuxApiMock/include/LinuxApiMock.h index f79f3f44..610ac970 100644 --- a/test/utils/LinuxApiMock/include/LinuxApiMock.h +++ b/test/utils/LinuxApiMock/include/LinuxApiMock.h @@ -3,6 +3,33 @@ #include #include #include +using ::testing::_; +using ::testing::Action; +using ::testing::ActionInterface; +using ::testing::Assign; +using ::testing::ByMove; +using ::testing::ByRef; +using ::testing::DefaultValue; +using ::testing::DoAll; +using ::testing::DoDefault; +using ::testing::IgnoreResult; +using ::testing::Invoke; +using ::testing::InvokeWithoutArgs; +using ::testing::MakePolymorphicAction; +using ::testing::PolymorphicAction; +using ::testing::Return; +using ::testing::ReturnNew; +using ::testing::ReturnNull; +using ::testing::ReturnPointee; +using ::testing::ReturnRef; +using ::testing::ReturnRefOfCopy; +using ::testing::ReturnRoundRobin; +using ::testing::SaveArg; +using ::testing::SetArgPointee; +using ::testing::SetArgumentPointee; +using ::testing::Unused; +using ::testing::WithArgs; +using ::testing::internal::BuiltInDefaultValue; constexpr int INVALID_HANDLE = -1; class LinuxApiMock { @@ -23,12 +50,25 @@ public: virtual int fx_open(const char *pathname, int flags); virtual int fx_tcgetattr(int fd, struct termios *termios_p); virtual int fx_tcsetattr(int fd, int optional_actions, const struct termios *termios_p); + virtual ssize_t fx_write(int fd, const void *buf, size_t count); + +public: + /** + * @brief + * + */ + // virtual void ApiLock(void) {} + /** + * @brief + * + */ + // virtual void ApiUnlock(void) {} }; /** * A simulation interface class used for automated testing in Ubuntu systems, implementing the function of piling on * some Linux standard interfaces. */ -class LinuxTest : public LinuxApiMock +class LinuxTest : public LinuxApiMock, public std::enable_shared_from_this { public: LinuxTest() = default; @@ -36,6 +76,7 @@ public: MOCK_METHOD2(fx_open, int(const char *, int)); MOCK_METHOD2(fx_tcgetattr, int(int, struct termios *)); MOCK_METHOD3(fx_tcsetattr, int(int, int, const struct termios *)); + MOCK_METHOD3(fx_write, ssize_t(int, const void *, size_t)); public: /** diff --git a/test/utils/LinuxApiMock/src/LinuxApiMock.cpp b/test/utils/LinuxApiMock/src/LinuxApiMock.cpp index d957f243..6236305f 100644 --- a/test/utils/LinuxApiMock/src/LinuxApiMock.cpp +++ b/test/utils/LinuxApiMock/src/LinuxApiMock.cpp @@ -7,7 +7,7 @@ int LinuxApiMock::fx_tcsetattr(int fd, int optional_actions, const struct termio { return __real_fx_tcsetattr(fd, optional_actions, termios_p); } - +ssize_t LinuxApiMock::fx_write(int fd, const void *buf, size_t count) { return __real_fx_write(fd, buf, count); } std::shared_ptr LinuxTest::CreateLinuxTest(void) { std::shared_ptr test = std::make_shared(); diff --git a/test/utils/LinuxApiMock/src/LinuxTestImpl.cpp b/test/utils/LinuxApiMock/src/LinuxTestImpl.cpp index d87b4459..5eef933c 100644 --- a/test/utils/LinuxApiMock/src/LinuxTestImpl.cpp +++ b/test/utils/LinuxApiMock/src/LinuxTestImpl.cpp @@ -14,30 +14,86 @@ */ #include "LinuxTestImpl.h" #include "ILog.h" +#include +/** + * @brief The simulated interface has been subjected to lock serial processing to ensure that the return value can be + * safely returned through multiple threads. However, this may affect the timing of the test code, which is not very + * reasonable. If the behavior of the simulated interface is redefined, the impact can be ignored. + * @param mock + */ void LinuxTestImpl::ApiInit(std::shared_ptr &mock) { + LogInfo("ApiInit\n"); static int openFd = -1; - auto api_open = [](const char *pathname, int flags) { + auto api_open = [=](const char *pathname, int flags) { LogInfo("Call __real_fx_open, pathname = %s.\n", pathname); openFd = __real_fx_open(pathname, flags); + LogInfo("openFd = %d\n", openFd); }; static int resultTcgetattr = -1; - auto api_tcgetattr = [](int fd, struct termios *termios_p) { + auto api_tcgetattr = [=](int fd, struct termios *termios_p) { resultTcgetattr = __real_fx_tcgetattr(fd, termios_p); LogInfo("resultTcgetattr = %d\n", resultTcgetattr); }; static int resultTcsetattr = -1; - auto api_tcsetattr = [](int fd, int optional_actions, const struct termios *termios_p) { + auto api_tcsetattr = [=](int fd, int optional_actions, const struct termios *termios_p) { resultTcsetattr = __real_fx_tcsetattr(fd, optional_actions, termios_p); LogInfo("resultTcsetattr = %d\n", resultTcsetattr); }; - EXPECT_CALL(*mock.get(), fx_open(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::DoAll(::testing::WithArgs<0, 1>(::testing::Invoke(api_open)), - ::testing::ReturnPointee(&openFd))); - EXPECT_CALL(*mock.get(), fx_tcgetattr(::testing::_, ::testing::_)) - .WillRepeatedly(::testing::DoAll(::testing::WithArgs<0, 1>(::testing::Invoke(api_tcgetattr)), - ::testing::ReturnPointee(&resultTcgetattr))); - EXPECT_CALL(*mock.get(), fx_tcsetattr(::testing::_, ::testing::_, ::testing::_)) - .WillRepeatedly(::testing::DoAll(::testing::WithArgs<0, 1, 2>(::testing::Invoke(api_tcsetattr)), - ::testing::ReturnPointee(&resultTcsetattr))); + static int writeLength = -1; + auto api_write = [=](int fd, const void *buf, size_t count) { + writeLength = __real_fx_write(fd, buf, count); + LogInfo("writeLength = %d\n", writeLength); + }; + EXPECT_CALL(*mock.get(), fx_open(_, _)) + .WillRepeatedly( + DoAll(Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + WithArgs<0, 1>(Invoke(api_open)), + Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiUnlockThread), + ReturnPointee(&openFd))); + EXPECT_CALL(*mock.get(), fx_tcgetattr(_, _)) + .WillRepeatedly(DoAll(Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + WithArgs<0, 1>(Invoke(api_tcgetattr)), + Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + ReturnPointee(&resultTcgetattr))); + EXPECT_CALL(*mock.get(), fx_tcsetattr(_, _, _)) + .WillRepeatedly(DoAll(Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + WithArgs<0, 1, 2>(Invoke(api_tcsetattr)), + Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + ReturnPointee(&resultTcsetattr))); + EXPECT_CALL(*mock.get(), fx_write(_, _, _)) + .WillRepeatedly(DoAll(Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + WithArgs<0, 1, 2>(Invoke(api_write)), + Invoke((std::dynamic_pointer_cast(mock)).get(), &LinuxTestImpl::ApiLock), + ReturnPointee(&writeLength))); +} +void LinuxTestImpl::Init() {} +void LinuxTestImpl::UnInit() +{ + if (mApiThread.joinable()) { + mApiThread.join(); + } +} +void LinuxTestImpl::ApiLock(void) +{ + mApiMutex.lock(); + LogInfo("lock api.\n"); +} +void LinuxTestImpl::ApiUnlock(void) +{ + mApiMutex.unlock(); + LogInfo("unlock api.\n"); +} +void LinuxTestImpl::ApiUnlockThread(void) +{ + LogInfo("ApiUnlockThread\n"); + if (mApiThread.joinable()) { + mApiThread.join(); + } + auto api_unlock = [](std::shared_ptr test) { + std::this_thread::sleep_for(std::chrono::milliseconds(API_LOCK_TIME_MS)); + test->ApiUnlock(); + }; + std::shared_ptr test = std::dynamic_pointer_cast(LinuxTest::shared_from_this()); + mApiThread = std::thread(api_unlock, test); } \ No newline at end of file diff --git a/test/utils/LinuxApiMock/src/LinuxTestImpl.h b/test/utils/LinuxApiMock/src/LinuxTestImpl.h index 14965769..1a5623c1 100644 --- a/test/utils/LinuxApiMock/src/LinuxTestImpl.h +++ b/test/utils/LinuxApiMock/src/LinuxTestImpl.h @@ -17,13 +17,33 @@ #include "HandleManager.h" #include "LinuxApiMock.h" #include "WrapApi.h" +#include +#include +/** + * @brief The simulated interface will be locked by default to ensure that the return value of the interface can be + * correctly obtained by the application in the default state. This is not very reasonable and should be optimized. + * This is the blocking time after locking, during which it is necessary to ensure that the application can obtain a + * global return value. + */ +constexpr int API_LOCK_TIME_MS = 5; class LinuxTestImpl : public HandleManager { public: LinuxTestImpl() = default; virtual ~LinuxTestImpl() = default; + void Init() override; + void UnInit() override; + void ApiLock(void); + void ApiUnlock(void); + +private: + void ApiUnlockThread(void); public: static void ApiInit(std::shared_ptr &mock); + +private: + std::mutex mApiMutex; + std::thread mApiThread; }; #endif \ No newline at end of file diff --git a/test/utils/LinuxApiMock/src/WrapApi.cpp b/test/utils/LinuxApiMock/src/WrapApi.cpp index 78869c29..ed59201a 100644 --- a/test/utils/LinuxApiMock/src/WrapApi.cpp +++ b/test/utils/LinuxApiMock/src/WrapApi.cpp @@ -1,3 +1,17 @@ +/* + * Copyright (c) 2023 Fancy Code. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include "WrapApi.h" #include "LinuxApiMock.h" #ifdef __cplusplus @@ -12,6 +26,10 @@ int __wrap_fx_tcsetattr(int fd, int optional_actions, const struct termios *term { return LinuxApiMock::GetInstance()->fx_tcsetattr(fd, optional_actions, termios_p); } +ssize_t __wrap_fx_write(int fd, const void *buf, size_t count) +{ + return LinuxApiMock::GetInstance()->fx_write(fd, buf, count); +} #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/test/utils/LinuxApiMock/src/WrapApi.h b/test/utils/LinuxApiMock/src/WrapApi.h index dc819c1e..260fe40c 100644 --- a/test/utils/LinuxApiMock/src/WrapApi.h +++ b/test/utils/LinuxApiMock/src/WrapApi.h @@ -14,6 +14,7 @@ */ #ifndef WRAP_API_H #define WRAP_API_H +#include #ifdef __cplusplus extern "C" { #endif @@ -21,6 +22,7 @@ extern "C" { int __real_fx_open(const char *pathname, int flags); int __real_fx_tcgetattr(int fd, struct termios *termios_p); int __real_fx_tcsetattr(int fd, int optional_actions, const struct termios *termios_p); +ssize_t __real_fx_write(int fd, const void *buf, size_t count); #ifdef __cplusplus } #endif diff --git a/test/utils/UartDevice/src_mock/UartDevice_Mock_Test.cpp b/test/utils/UartDevice/src_mock/UartDevice_Mock_Test.cpp index 80e1cd28..859d2a11 100644 --- a/test/utils/UartDevice/src_mock/UartDevice_Mock_Test.cpp +++ b/test/utils/UartDevice/src_mock/UartDevice_Mock_Test.cpp @@ -18,6 +18,7 @@ #include "UartDeviceTestTool.h" #include #include +#include namespace UartDeviceMockTest { const char *gDeviceName = "dev/s1"; @@ -45,9 +46,16 @@ public: mLinuxTest = LinuxTest::CreateLinuxTest(); std::shared_ptr test = mLinuxTest; LinuxApiMock::GetInstance(&test); - UartDeviceDefaultInit(mLinuxTest, gUartDevice); + LinuxApiMock::GetInstance()->Init(); + // UartDeviceDefaultInit(mLinuxTest, gUartDevice); + } + virtual void TearDown() + { + LinuxApiMock::GetInstance()->UnInit(); + mLinuxTest = std::make_shared(); + std::shared_ptr test = std::make_shared(); + LinuxApiMock::GetInstance(&test); } - virtual void TearDown() {} public: std::shared_ptr mLinuxTest; @@ -62,4 +70,23 @@ TEST_F(UartDeviceMockTest, Demo) // IUartTcflush(object); IUartDeviceFree(object); } +// ../output_files/test/bin/UartDeviceTest --gtest_filter=UartDeviceMockTest.Test +TEST_F(UartDeviceMockTest, Test) +{ + auto openThread = [](void) { + LogInfo("===========openThread \n"); + void *object = CreateUartDevice(gUartDevice); + IUartOpen(object); + IUartDeviceFree(object); + }; + std::thread test1 = std::thread(openThread); + test1.detach(); + std::thread test2 = std::thread(openThread); + test2.detach(); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + // std::thread(openThread2); + // IUartSend(object, nullptr, 0); + // IUartRecv(object, nullptr, 0, 0); + // IUartTcflush(object); +} } // namespace UartDeviceMockTest \ No newline at end of file diff --git a/utils/LinuxApi/include/LinuxApi.h b/utils/LinuxApi/include/LinuxApi.h index 3421b478..c5b5d3c3 100644 --- a/utils/LinuxApi/include/LinuxApi.h +++ b/utils/LinuxApi/include/LinuxApi.h @@ -14,7 +14,9 @@ */ #ifndef LINUX_API_H #define LINUX_API_H +#include #include +#include #ifdef __cplusplus extern "C" { #endif @@ -22,6 +24,7 @@ int fx_system(const char *command); int fx_open(const char *pathname, int flags); int fx_tcgetattr(int fd, struct termios *termios_p); int fx_tcsetattr(int fd, int optional_actions, const struct termios *termios_p); +ssize_t fx_write(int fd, const void *buf, size_t count); #ifdef __cplusplus } #endif diff --git a/utils/LinuxApi/src/LinuxApi.c b/utils/LinuxApi/src/LinuxApi.c index 8d93ec17..075b5552 100644 --- a/utils/LinuxApi/src/LinuxApi.c +++ b/utils/LinuxApi/src/LinuxApi.c @@ -23,9 +23,14 @@ #include int fx_system(const char *command) { return system(command); } -int fx_open(const char *pathname, int flags) { return open(pathname, flags); } +int fx_open(const char *pathname, int flags) +{ + // printf("ssssssssssssssssssssssssssssssss\n"); + return open(pathname, flags); +} int fx_tcgetattr(int fd, struct termios *termios_p) { return tcgetattr(fd, termios_p); } int fx_tcsetattr(int fd, int optional_actions, const struct termios *termios_p) { return tcsetattr(fd, optional_actions, termios_p); -} \ No newline at end of file +} +ssize_t fx_write(int fd, const void *buf, size_t count) { return write(fd, buf, count); } \ No newline at end of file diff --git a/utils/UartDevice/src/UartDeviceImpl.cpp b/utils/UartDevice/src/UartDeviceImpl.cpp index c7b18090..c20d6b3f 100644 --- a/utils/UartDevice/src/UartDeviceImpl.cpp +++ b/utils/UartDevice/src/UartDeviceImpl.cpp @@ -47,6 +47,7 @@ const size_t UartDeviceImpl::UartSend(const char *buff, const size_t &buffLength } // TODO: what if write return less then buffLength? len = write(mFd, buff, buffLength); + LogInfo("len = %d\n", len); if (len == buffLength) { return len; }