Improve:Optimize multi-threaded security vulnerabilities in test code.
This commit is contained in:
parent
c6ab66d3ec
commit
328b12abc9
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
/**
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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); }
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user