Improve:Optimize multi-threaded security vulnerabilities in test code.

This commit is contained in:
fancy 2024-01-28 06:08:47 -08:00
parent c6ab66d3ec
commit 328b12abc9
11 changed files with 192 additions and 19 deletions

View File

@ -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)

View File

@ -3,6 +3,33 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
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<LinuxTest>
{
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:
/**

View File

@ -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> LinuxTest::CreateLinuxTest(void)
{
std::shared_ptr<LinuxTest> test = std::make_shared<LinuxTestImpl>();

View File

@ -14,30 +14,86 @@
*/
#include "LinuxTestImpl.h"
#include "ILog.h"
#include <thread>
/**
* @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<LinuxTest> &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<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_open)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiUnlockThread),
ReturnPointee(&openFd)));
EXPECT_CALL(*mock.get(), fx_tcgetattr(_, _))
.WillRepeatedly(DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1>(Invoke(api_tcgetattr)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
ReturnPointee(&resultTcgetattr)));
EXPECT_CALL(*mock.get(), fx_tcsetattr(_, _, _))
.WillRepeatedly(DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1, 2>(Invoke(api_tcsetattr)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
ReturnPointee(&resultTcsetattr)));
EXPECT_CALL(*mock.get(), fx_write(_, _, _))
.WillRepeatedly(DoAll(Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(mock)).get(), &LinuxTestImpl::ApiLock),
WithArgs<0, 1, 2>(Invoke(api_write)),
Invoke((std::dynamic_pointer_cast<LinuxTestImpl>(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<LinuxTestImpl> test) {
std::this_thread::sleep_for(std::chrono::milliseconds(API_LOCK_TIME_MS));
test->ApiUnlock();
};
std::shared_ptr<LinuxTestImpl> test = std::dynamic_pointer_cast<LinuxTestImpl>(LinuxTest::shared_from_this());
mApiThread = std::thread(api_unlock, test);
}

View File

@ -17,13 +17,33 @@
#include "HandleManager.h"
#include "LinuxApiMock.h"
#include "WrapApi.h"
#include <mutex>
#include <thread>
/**
* @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<LinuxTest> &mock);
private:
std::mutex mApiMutex;
std::thread mApiThread;
};
#endif

View File

@ -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

View File

@ -14,6 +14,7 @@
*/
#ifndef WRAP_API_H
#define WRAP_API_H
#include <unistd.h>
#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

View File

@ -18,6 +18,7 @@
#include "UartDeviceTestTool.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <thread>
namespace UartDeviceMockTest
{
const char *gDeviceName = "dev/s1";
@ -45,9 +46,16 @@ public:
mLinuxTest = LinuxTest::CreateLinuxTest();
std::shared_ptr<LinuxApiMock> test = mLinuxTest;
LinuxApiMock::GetInstance(&test);
UartDeviceDefaultInit(mLinuxTest, gUartDevice);
LinuxApiMock::GetInstance()->Init();
// UartDeviceDefaultInit(mLinuxTest, gUartDevice);
}
virtual void TearDown()
{
LinuxApiMock::GetInstance()->UnInit();
mLinuxTest = std::make_shared<LinuxTest>();
std::shared_ptr<LinuxApiMock> test = std::make_shared<LinuxApiMock>();
LinuxApiMock::GetInstance(&test);
}
virtual void TearDown() {}
public:
std::shared_ptr<LinuxTest> 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

View File

@ -14,7 +14,9 @@
*/
#ifndef LINUX_API_H
#define LINUX_API_H
#include <stddef.h>
#include <termios.h>
#include <unistd.h>
#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

View File

@ -23,9 +23,14 @@
#include <unistd.h>
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);
}
}
ssize_t fx_write(int fd, const void *buf, size_t count) { return write(fd, buf, count); }

View File

@ -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;
}