Subject: [PATCH] 升级补丁
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -23,6 +23,7 @@
#include <list>
#include <utility>
#include <algorithm>
+#include <mutex>
MOCKCPP_NS_START
@@ -49,10 +50,14 @@
InvocationMocker* findInvocationMocker(const std::string& id) const;
void reset();
+ void reset(ChainableMockMethodKey* key);
void verify();
bool verified;
List methods;
+
+private:
+ mutable std::mutex mtx;
};
/////////////////////////////////////////////////////////////////////////
@@ -81,10 +86,30 @@
}
}
+/////////////////////////////////////////////////////////////////////////
+namespace
+{
+ struct IsMethodKeyMatch
+ {
+ IsMethodKeyMatch(ChainableMockMethodKey* key)
+ : myKey(key)
+ {}
+
+ bool operator()(ChainableMockMethodContainerImpl::ValueType value)
+ {
+ return myKey->equals(getKey(value));
+ }
+
+ ChainableMockMethodKey* myKey;
+ };
+
+}
+
/////////////////////////////////////////////////////////////////////////
void
ChainableMockMethodContainerImpl::reset()
{
+ std::lock_guard<std::mutex> lock(mtx);
//for_each(methods.begin(), methods.end(), resetMethod);
for(Iterator i = methods.begin(); i != methods.end(); i++)
{
@@ -107,6 +132,7 @@
void
ChainableMockMethodContainerImpl::verify()
{
+ std::lock_guard<std::mutex> lock(mtx);
if(verified) return;
verified = true;
@@ -114,6 +140,20 @@
for_each(methods.begin(), methods.end(), verifyMethod);
}
+void
+ChainableMockMethodContainerImpl::reset(ChainableMockMethodKey* key)
+{
+ std::lock_guard<std::mutex> lock(mtx);
+ ConstIterator i = std::find_if(methods.begin()
+ , methods.end()
+ , IsMethodKeyMatch(key));
+
+ if (i != methods.end()) {
+ resetMethod(*i);
+ methods.remove(*i);
+ }
+}
+
/////////////////////////////////////////////////////////////////////////
ChainableMockMethodContainerImpl::~ChainableMockMethodContainerImpl()
{
@@ -125,6 +165,7 @@
ChainableMockMethodContainerImpl::addMethod(ChainableMockMethodKey* key, \
ChainableMockMethodCore* method)
{
+ std::lock_guard<std::mutex> lock(mtx);
methods.push_back(ValueType(key, method));
}
@@ -144,6 +185,7 @@
InvocationMocker*
ChainableMockMethodContainerImpl::findInvocationMocker(const std::string& id) const
{
+ std::lock_guard<std::mutex> lock(mtx);
for (ConstIterator i = methods.begin(); i != methods.end(); ++i)
{
InvocationMocker* mocker = i->second->getInvocationMocker(id);
@@ -156,29 +198,11 @@
return 0;
}
-/////////////////////////////////////////////////////////////////////////
-namespace
-{
- struct IsMethodKeyMatch
- {
- IsMethodKeyMatch(ChainableMockMethodKey* key)
- : myKey(key)
- {}
-
- bool operator()(ChainableMockMethodContainerImpl::ValueType value)
- {
- return myKey->equals(getKey(value));
- }
-
- ChainableMockMethodKey* myKey;
- };
-
-}
-
/////////////////////////////////////////////////////////////////////////
ChainableMockMethodCore*
ChainableMockMethodContainerImpl::getMethod(ChainableMockMethodKey* key) const
{
+ std::lock_guard<std::mutex> lock(mtx);
ConstIterator i = std::find_if( methods.begin()
, methods.end()
, IsMethodKeyMatch(key));
@@ -227,6 +251,12 @@
This->verify();
}
+void
+ChainableMockMethodContainer::reset(ChainableMockMethodKey* key)
+{
+ This->reset(key);
+}
+
/////////////////////////////////////////////////////////////////////////
MOCKCPP_NS_END
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
new file mode 100644
@@ -0,0 +1,180 @@
+/***
+ mockcpp is a generic C/C++ mock framework.
+ Copyright (C) <2021> <Zhao Yonggang: yonggang.zhao@icloud.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <cstring>
+#include <mockcpp/mokc.h>
+#include <testngpp/testngpp.hpp>
+
+
+
+USING_TESTNGPP_NS
+USING_MOCKCPP_NS
+
+void foo(char *out) {
+ *out = 0;
+}
+
+void bar(int *out) {
+ out[0] = 0;
+ out[1] = 1;
+ out[2] = 2;
+}
+
+void baz(int *out) {
+ *out = 0;
+}
+
+FIXTURE(OutBoundP)
+{
+ TEST(outBoundP should not outBoundP different type with input parameter)
+ {
+ unsigned char array[10] = "hostname";
+ MOCKER(foo).stubs().with(outBoundP(array, std::strlen((char *)array))).will(returnValue(10));
+ char buffer[10] = {0};
+ ASSERT_THROWS_ANYTHING(foo(buffer));
+ GlobalMockObject::verify();
+ }
+
+ TEST(outBoundP for array output parameter)
+ {
+ int array[] = {0, 10, 20};
+ MOCKER(bar).stubs().with(outBoundP(array, sizeof(array)));
+ int out[3];
+ bar(out);
+ ASSERT_EQ(out[0], 0);
+ ASSERT_EQ(out[1], 10);
+ ASSERT_EQ(out[2], 20);
+ GlobalMockObject::verify();
+ }
+
+ TEST(outBoundP for output value parameter)
+ {
+ int val = 10;
+ MOCKER(baz).stubs().with(outBoundP(&val));
+ int out;
+ baz(&out);
+ ASSERT_EQ(out, 10);
+ GlobalMockObject::verify();
+ }
+
+ TEST(outBoundP reset specified function for different prototype 1)
+ {
+ char c = 10;
+ int i = 20;
+ MOCKER(foo).stubs().with(outBoundP(&c));
+ MOCKER(baz).stubs().with(outBoundP(&i));
+ char outc;
+ int outi;
+ foo(&outc);
+ baz(&outi);
+ ASSERT_EQ(10, outc);
+ ASSERT_EQ(20, outi);
+ GlobalMockObject::reset((const void *)foo);
+ foo(&outc);
+ baz(&outi);
+ ASSERT_EQ(0, outc);
+ ASSERT_EQ(20, outi);
+ char c1 = 100;
+ MOCKER(foo).stubs().with(outBoundP(&c1));
+ foo(&outc);
+ baz(&outi);
+ ASSERT_EQ(100, outc);
+ ASSERT_EQ(20, outi);
+ GlobalMockObject::verify();
+ }
+
+ TEST(outBoundP reset specified function for different prototype 2)
+ {
+ char c = 10;
+ int i = 20;
+ MOCKER(foo).stubs().with(outBoundP(&c));
+ MOCKER(baz).stubs().with(outBoundP(&i));
+ char outc;
+ int outi;
+ foo(&outc);
+ baz(&outi);
+ ASSERT_EQ(10, outc);
+ ASSERT_EQ(20, outi);
+ GlobalMockObject::reset((const void *)baz);
+ foo(&outc);
+ baz(&outi);
+ ASSERT_EQ(10, outc);
+ ASSERT_EQ(0, outi);
+ int i1 = 200;
+ MOCKER(baz).stubs().with(outBoundP(&i1));
+ foo(&outc);
+ baz(&outi);
+ ASSERT_EQ(10, outc);
+ ASSERT_EQ(200, outi);
+ GlobalMockObject::verify();
+ }
+
+ TEST(outBoundP reset specified function for same prototype 1)
+ {
+ int r = 10;
+ int z = 20;
+ MOCKER(bar).stubs().with(outBoundP(&r));
+ MOCKER(baz).stubs().with(outBoundP(&z));
+ int outr[3];
+ int outz;
+ bar((int *)outr);
+ baz(&outz);
+ ASSERT_EQ(10, outr[0]);
+ ASSERT_EQ(20, outz);
+ GlobalMockObject::reset((const void *)bar);
+ bar((int *)outr);
+ baz(&outz);
+ ASSERT_EQ(0, outr[0]);
+ ASSERT_EQ(1, outr[1]);
+ ASSERT_EQ(2, outr[2]);
+ ASSERT_EQ(20, outz);
+ int r1 = 100;
+ MOCKER(bar).stubs().with(outBoundP(&r1));
+ bar((int *)outr);
+ baz(&outz);
+ ASSERT_EQ(100, outr[0]);
+ ASSERT_EQ(20, outz);
+ GlobalMockObject::verify();
+ }
+
+ TEST(outBoundP reset specified function for same prototype 2)
+ {
+ int r = 10;
+ int z = 20;
+ MOCKER(bar).stubs().with(outBoundP(&r));
+ MOCKER(baz).stubs().with(outBoundP(&z));
+ int outr[3];
+ int outz;
+ bar((int *)outr);
+ baz(&outz);
+ ASSERT_EQ(10, outr[0]);
+ ASSERT_EQ(20, outz);
+ GlobalMockObject::reset((const void *)baz);
+ bar((int *)outr);
+ baz(&outz);
+ ASSERT_EQ(10, outr[0]);
+ ASSERT_EQ(0, outz);
+ int z1 = 200;
+ MOCKER(baz).stubs().with(outBoundP(&z1));
+ bar((int *)outr);
+ baz(&outz);
+ ASSERT_EQ(10, outr[0]);
+ ASSERT_EQ(200, outz);
+ GlobalMockObject::verify();
+ }
+};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
new file mode 100644
@@ -0,0 +1,79 @@
+/***
+ mockcpp is a generic C/C++ mock framework.
+ Copyright (C) <2009> <Darwin Yuan: darwin.yuan@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <mockcpp/mokc.h>
+#include <testcpp/testcpp.hpp>
+#include <thread>
+#include <unistd.h>
+
+USING_MOCKCPP_NS
+
+int foo(int *a)
+{
+ *a = 1;
+ return 1;
+}
+
+int bar(int *a)
+{
+ *a = 2;
+ return 2;
+}
+
+int check_ret_cnt;
+void check_ret()
+{
+ check_ret_cnt = 0;
+ for (int i = 0; i < 10001; i++) {
+ int out;
+ int ret = foo(&out);
+ check_ret_cnt++;
+ usleep(1);
+ }
+}
+
+int check_out_cnt;
+void check_out()
+{
+ check_out_cnt = 0;
+ for (int i = 0; i < 9999; i++) {
+ int out;
+ int ret = foo(&out);
+ check_out_cnt++;
+ usleep(1);
+ }
+}
+
+class TestMockMutlThread : public TESTCPP_NS::TestFixture
+{
+public:
+ void setUp() { }
+ void tearDown() { }
+
+ void testConcurrentExecutionWithoutThrowingExceptions()
+ {
+ MOCKER(foo).stubs().will(invoke(bar));
+ std::thread thread1(check_ret);
+ std::thread thread2(check_out);
+ thread1.join();
+ thread2.join();
+ TS_ASSERT_EQUALS(check_ret_cnt, 10001);
+ TS_ASSERT_EQUALS(check_out_cnt, 9999);
+ GlobalMockObject::verify();
+ }
+};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -47,5 +47,10 @@
instance.reset();
}
+void GlobalMockObject::reset(const void *api)
+{
+ instance.reset(api);
+}
+
MOCKCPP_NS_END
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -18,6 +18,7 @@
#ifndef __MOCKCPP_API_HOOK_FUNCTOR_H__
#define __MOCKCPP_API_HOOK_FUNCTOR_H__
+#include <mutex>
#include <mockcpp/mockcpp.h>
#include <mockcpp/GlobalMockObject.h>
@@ -39,8 +40,9 @@
\
static R CallingConvention hook(DECL_PARAMS_LIST(n)) \
{ \
- return GlobalMockObject::instance.invoke<R>(apiAddress) \
- (empty_caller DECL_REST_PARAMS(n)); \
+ auto func = GlobalMockObject::instance.invoke<R>(apiAddress); \
+ std::lock_guard<std::mutex> lock(mtx); \
+ return func(empty_caller DECL_REST_PARAMS(n)); \
} \
\
static bool appliedBy(F* api) \
@@ -77,23 +79,26 @@
private: \
static void* apiAddress; \
static unsigned int refCount; \
+ static std::mutex mtx; \
}; \
template <typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
void* ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq>::apiAddress = 0; \
+template <typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+std::mutex ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq>::mtx; \
template <typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
-unsigned int ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq>::refCount = 0
+unsigned int ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq>::refCount = 0
#if defined(_MSC_VER)
// TODO: ApiHook related tests failed on VS2019.
// [ ERROR ] TestApiHook.h:66: hardware exception STATUS_ILLEGAL_INSTRUCTION raised in setup or running test
// [ ERROR ] TestApiHook.h:66 : hardware exception STATUS_ACCESS_VIOLATION raised in teardown
-#if _MSC_VER >= 1920 // VS 2019
+#if _MSC_VER >= 1920 // VS 2019
#define MOCKCPP_API_HOOK_FUNCTOR_DEF(n) \
__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, __stdcall)
#else
#define MOCKCPP_API_HOOK_FUNCTOR_DEF(n) \
__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, ); \
-__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, __stdcall)
+__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, __stdcall)
#endif
#else
#define MOCKCPP_API_HOOK_FUNCTOR_DEF(n) \
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
new file mode 100644
@@ -0,0 +1,114 @@
+/***
+ mockcpp is a generic C/C++ mock framework.
+ Copyright (C) <2009> <Darwin Yuan: darwin.yuan@gmail.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <testcpp/testcpp.hpp>
+#include <mockcpp/mokc.h>
+
+USING_MOCKCPP_NS
+
+class mytest {
+public:
+ int func(int a, int b, int c, int d);
+ int func_void();
+};
+
+class stub {
+public:
+ static int func(void *p, int a, int b, int c, int d);
+ static int func_void(void *p);
+};
+
+int mytest::func(int a, int b, int c, int d)
+{
+ return a + b + c + d;
+}
+
+int mytest::func_void()
+{
+ int arr[2] = {10, 20};
+ return arr[0] + arr[1];
+}
+
+int stub::func(void *p, int a, int b, int c, int d)
+{
+ return 2 * (a + b + c + d);
+}
+
+int stub::func_void(void *p)
+{
+ int arr[2] = {10, 20};
+ return 2 * (arr[0] + arr[1]);
+}
+
+int stub_func(void *p, int a, int b, int c, int d)
+{
+ return 2 * (a + b + c + d);
+}
+
+class TestMockClassPublic : public TESTCPP_NS::TestFixture
+{
+public:
+ void setUp() { }
+ void tearDown() { }
+
+/*
+LLVM兼容绝大部分GNU的功能,但是对于一些认为不合理的功能则选择永不支持。此处将成员函数地址类型强转为一般函数地址类型即是此类功能。
+如下url的信息展示了不支持此类功能的具体解释: https://github.com/llvm/llvm-project/issues/22495
+*/
+#ifndef __clang__
+ void testMockWithClassStaticMember()
+ {
+ mytest inst;
+ MOCKER_CPP(&mytest::func, int (*)(void *, int, int, int, int)).stubs().will(invoke(stub::func));
+ int ret = inst.func(10, 20, 30, 40);
+ TS_ASSERT(ret == 200);
+ GlobalMockObject::verify();
+ }
+
+ void testMockWithNormalCFunction()
+ {
+ mytest inst;
+ MOCKER_CPP(&mytest::func, int (*)(void *, int, int, int, int)).stubs().will(invoke(stub_func));
+ int ret = inst.func(10, 20, 30, 40);
+ TS_ASSERT(ret == 200);
+ GlobalMockObject::verify();
+ }
+
+ void testMockWithClassStaticMemberVoid()
+ {
+ mytest inst;
+ MOCKER_CPP(&mytest::func_void, int (*)(void *)).stubs().will(invoke(stub::func_void));
+ int ret = inst.func_void();
+ TS_ASSERT(ret == 60);
+ GlobalMockObject::verify();
+ }
+#else
+ void testMockWithClassStaticMember()
+ {
+ }
+
+ void testMockWithNormalCFunction()
+ {
+ }
+
+ void testMockWithClassStaticMemberVoid()
+ {
+ }
+#endif
+};
+
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -41,6 +41,7 @@
void addMethod(void* methodAddr, unsigned int indexOfVtbl, unsigned int indexofVptr = 0);
void setDestructor(unsigned int vptrIndex, unsigned int vtblIndex);
+ void reset(unsigned int vptrIndex, unsigned int vtblIndex);
void expectsBeingDeleted();
void expectsKeepAlive();
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
new file mode 100644
@@ -0,0 +1,226 @@
+#include <testngpp/internal/TestCase.h>
+#include <testngpp/internal/TestFixtureDesc.h>
+#include <testngpp/internal/TestSuiteDesc.h>
+#include <testngpp/internal/DataDriven.h>
+#include "TestMockClassPublic.h"
+
+static struct TESTCASE_TestMockClassPublic_testMockWithClassStaticMember
+ : public TESTNGPP_NS::TestCase
+{
+ TESTCASE_TestMockClassPublic_testMockWithClassStaticMember()
+ : TESTNGPP_NS::TestCase
+ ( "testMockWithClassStaticMember"
+ , "TestMockClassPublic"
+ , "TestMockClassPublic"
+ , 0
+ , "TestMockClassPublic.h"
+ , 69)
+ {}
+
+ void setFixture(TESTNGPP_NS::TestFixture* fixture)
+ {
+ if(fixture == 0)
+ {
+ belongedFixture = new TestMockClassPublic();
+ }
+ else
+ {
+ belongedFixture = dynamic_cast<TestMockClassPublic*>(fixture);
+ }
+ }
+
+ void runTest()
+ {
+
+belongedFixture->testMockWithClassStaticMember()
+;
+ }
+
+ TESTNGPP_NS::TestFixture* getFixture() const
+ {
+ return belongedFixture;
+ }
+
+ unsigned int numberOfTags() const
+ {
+ return 0;
+ }
+
+ const char** getTags() const
+ {
+ static const char* tags[] = {0};
+ return tags;
+ }
+
+ const char* getMemCheckSwitch() const
+ {
+ static const char* memCheckSwitch = "none";
+ return memCheckSwitch;
+ }
+
+private:
+ TestMockClassPublic* belongedFixture;
+} testcase_instance_TestMockClassPublic_testMockWithClassStaticMember ;
+
+
+
+static struct TESTCASE_TestMockClassPublic_testMockWithNormalCFunction
+ : public TESTNGPP_NS::TestCase
+{
+ TESTCASE_TestMockClassPublic_testMockWithNormalCFunction()
+ : TESTNGPP_NS::TestCase
+ ( "testMockWithNormalCFunction"
+ , "TestMockClassPublic"
+ , "TestMockClassPublic"
+ , 0
+ , "TestMockClassPublic.h"
+ , 78)
+ {}
+
+ void setFixture(TESTNGPP_NS::TestFixture* fixture)
+ {
+ if(fixture == 0)
+ {
+ belongedFixture = new TestMockClassPublic();
+ }
+ else
+ {
+ belongedFixture = dynamic_cast<TestMockClassPublic*>(fixture);
+ }
+ }
+
+ void runTest()
+ {
+
+belongedFixture->testMockWithNormalCFunction()
+;
+ }
+
+ TESTNGPP_NS::TestFixture* getFixture() const
+ {
+ return belongedFixture;
+ }
+
+ unsigned int numberOfTags() const
+ {
+ return 0;
+ }
+
+ const char** getTags() const
+ {
+ static const char* tags[] = {0};
+ return tags;
+ }
+
+ const char* getMemCheckSwitch() const
+ {
+ static const char* memCheckSwitch = "none";
+ return memCheckSwitch;
+ }
+
+private:
+ TestMockClassPublic* belongedFixture;
+} testcase_instance_TestMockClassPublic_testMockWithNormalCFunction ;
+
+
+
+static struct TESTCASE_TestMockClassPublic_testMockWithClassStaticMemberVoid
+ : public TESTNGPP_NS::TestCase
+{
+ TESTCASE_TestMockClassPublic_testMockWithClassStaticMemberVoid()
+ : TESTNGPP_NS::TestCase
+ ( "testMockWithClassStaticMemberVoid"
+ , "TestMockClassPublic"
+ , "TestMockClassPublic"
+ , 0
+ , "TestMockClassPublic.h"
+ , 87)
+ {}
+
+ void setFixture(TESTNGPP_NS::TestFixture* fixture)
+ {
+ if(fixture == 0)
+ {
+ belongedFixture = new TestMockClassPublic();
+ }
+ else
+ {
+ belongedFixture = dynamic_cast<TestMockClassPublic*>(fixture);
+ }
+ }
+
+ void runTest()
+ {
+
+belongedFixture->testMockWithClassStaticMemberVoid()
+;
+ }
+
+ TESTNGPP_NS::TestFixture* getFixture() const
+ {
+ return belongedFixture;
+ }
+
+ unsigned int numberOfTags() const
+ {
+ return 0;
+ }
+
+ const char** getTags() const
+ {
+ static const char* tags[] = {0};
+ return tags;
+ }
+
+ const char* getMemCheckSwitch() const
+ {
+ static const char* memCheckSwitch = "none";
+ return memCheckSwitch;
+ }
+
+private:
+ TestMockClassPublic* belongedFixture;
+} testcase_instance_TestMockClassPublic_testMockWithClassStaticMemberVoid ;
+
+
+
+static TESTNGPP_NS::TestCase* g_TESTCASEARRAY_TestMockClassPublic[] = {
+&testcase_instance_TestMockClassPublic_testMockWithClassStaticMember,
+&testcase_instance_TestMockClassPublic_testMockWithNormalCFunction,
+&testcase_instance_TestMockClassPublic_testMockWithClassStaticMemberVoid,
+0
+};
+
+
+
+
+/*static*/ TESTNGPP_NS::TestFixtureDesc test_fixture_desc_instance_TestMockClassPublic
+ ( "TestMockClassPublic"
+ , "TestMockClassPublic.h"
+ , g_TESTCASEARRAY_TestMockClassPublic
+ , (sizeof(g_TESTCASEARRAY_TestMockClassPublic)/sizeof(g_TESTCASEARRAY_TestMockClassPublic[0])) - 1
+ );
+
+
+
+static TESTNGPP_NS::TestFixtureDesc* array_of_fixture_desc_TestMockClassPublic[] = {
+&test_fixture_desc_instance_TestMockClassPublic,
+0
+};
+
+
+
+
+static TESTNGPP_NS::TestSuiteDesc test_suite_desc_instance_TestMockClassPublic
+ ( "TestMockClassPublic"
+ , array_of_fixture_desc_TestMockClassPublic
+ , (sizeof(array_of_fixture_desc_TestMockClassPublic)/sizeof(array_of_fixture_desc_TestMockClassPublic[0])) - 1
+ );
+
+
+
+extern "C" DLL_EXPORT TESTNGPP_NS::TestSuiteDesc* ___testngpp_test_suite_desc_getter() {
+ return &test_suite_desc_instance_TestMockClassPublic;
+}
+
+
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -59,6 +59,11 @@
bool evalSelf(const RefAny& val) const
{
+ if(!any_castable<T*>(val))
+ {
+ return false;
+ }
+
T* p = any_cast<T*>(val);
if (p == 0)
{
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -4,6 +4,7 @@
PROJECT(mockcpp)
INCLUDE(ProjectVar.txt)
+add_compile_options(-D_GLIBCXX_USE_CXX11_ABI=0)
ADD_SUBDIRECTORY(src)
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -53,6 +53,8 @@
MethodDescriptionUnion<Method> m;
m.method = input;
+/* 在arm32平台thumb指令集下, 函数指针地址可以是奇数 */
+#ifndef __arm__
oss_t oss;
oss << "Method address should be even, please make sure the method "
<< TypeString<Method>::value() << " is NOT a virtual method";
@@ -60,7 +62,7 @@
MOCKCPP_ASSERT_TRUE(
oss.str(),
!(m.desc.u.index%2));
-
+#endif
return m.desc.u.addr;
}
@@ -73,13 +75,24 @@
MethodDescriptionUnion<ExpectedMethodType> m;
m.method = input;
+// 在arm64和arm32平台下虚函数的 Method 与x86平台的值不同,需要做特殊处理
+#if defined(__aarch64__) || defined(__arm__)
+ m.desc.u.index++;
+ if (m.desc.delta >= 16)
+ m.desc.delta -= sizeof(void *);
+#endif
+
+/* 在arm32平台thumb指令集下, 虚函数地址不适用这个检查 */
+#ifndef __arm__
oss_t oss;
oss << "Virtual method address should be odd, please make sure the method "
- << TypeString<Method>::value() << " is a virtual method";
+ << TypeString<Method>::value() << " is a virtual method. index is "
+ << m.desc.u.index << ", delta is " << m.desc.delta << ".";
MOCKCPP_ASSERT_TRUE(
oss.str(),
- (m.desc.u.index%2));
+ (m.desc.u.index%2) && (m.desc.delta < 16 && m.desc.delta >= 0));
+#endif
return m.desc;
}
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -23,8 +23,14 @@
USER_CHOOSED_COMPILER_MAJOR_VER=""
# script usage 1: no parameter, use GNU compiler
+if [ "$1" == "llvm" ]; then
+AUTO_COMPILER="LLVM"
+AUTO_CXX_VER=`clang -dumpversion | awk -F. '{print $1}'`
+COMPILER_DEF="-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++"
+else
AUTO_COMPILER="GNU"
AUTO_CXX_VER=`gcc -dumpversion | awk -F. '{print $1}'`
+fi
InitEnviroment $AUTO_COMPILER $AUTO_CXX_VER
# script usage 2: input the compiler name and major version
@@ -42,9 +48,9 @@
#if [ $3 != "test" ]; then
-cmake -S . -B $BUILD_DIR/mockcpp
-cmake -S tests/3rdparty/testngpp -B $BUILD_DIR/mockcpp_testngpp
-cmake -S tests -B $BUILD_DIR/mockcpp_tests
+cmake $COMPILER_DEF -S . -B $BUILD_DIR/mockcpp
+cmake $COMPILER_DEF -S tests/3rdparty/testngpp -B $BUILD_DIR/mockcpp_testngpp
+cmake $COMPILER_DEF -S tests -B $BUILD_DIR/mockcpp_tests
CompileProject $MY_CXX_COMPILER_NAME $BUILD_DIR/mockcpp
CompileProject $MY_CXX_COMPILER_NAME $BUILD_DIR/mockcpp_testngpp
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -18,21 +18,20 @@
#include <string.h>
#include <inttypes.h>
#include <sys/mman.h>
+#include <unistd.h>
#include <mockcpp/CodeModifier.h>
-#define PAGE_ALIGN_BITS 12
-
//////////////////////////////////////////////////////////////////
-#define PAGE_SIZE (1 << PAGE_ALIGN_BITS)
-#define ALIGN_TO_PAGE_BOUNDARY(addr) (void*) (((uintptr_t)addr) & (~((1<<(PAGE_ALIGN_BITS))-1)))
+#define ALIGN_TO_PAGE_BOUNDARY(addr, page_size) (void*) (((uintptr_t)addr) & (~(page_size - 1)))
//////////////////////////////////////////////////////////////////
MOCKCPP_NS_START
bool CodeModifier::modify(void *dest, const void *src, size_t size)
{
- if(::mprotect(ALIGN_TO_PAGE_BOUNDARY(dest), PAGE_SIZE * 2, PROT_EXEC | PROT_WRITE | PROT_READ ) != 0)
+ int page_size = getpagesize();
+ if(::mprotect(ALIGN_TO_PAGE_BOUNDARY(dest, page_size), page_size * 2, PROT_EXEC | PROT_WRITE | PROT_READ ) != 0)
{
return false;
}
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -30,6 +30,7 @@
# define MOCKER(api) MOCKCPP_NS::mockAPI(#api, api)
# endif
+# define MOCKER_CPP(api, TT) (MOCKCPP_NS::mockAPI((#api), (reinterpret_cast<TT>(api))))
USING_MOCKCPP_NS
#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -19,10 +19,14 @@
#include <mockcpp/mockcpp.h>
-#if BUILD_FOR_X64
+#if defined(BUILD_FOR_X64)
# include "JmpCodeX64.h"
-#elif BUILD_FOR_X86
+#elif defined(BUILD_FOR_X86)
# include "JmpCodeX86.h"
+#elif defined(BUILD_FOR_AARCH64)
+# include "JmpCodeAArch64.h"
+#elif defined(BUILD_FOR_AARCH32)
+# include "JmpCodeAArch32.h"
#endif
#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -47,6 +47,7 @@
}
void reset();
+ void reset(const void* api);
private:
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -46,6 +46,7 @@
ChainableMockMethodContainer* container;
void reset();
+ void reset(unsigned int vptrIndex, unsigned int vtblIndex);
private:
@@ -107,6 +108,13 @@
return method;
}
+////////////////////////////////////////////////////////////////////////
+void MockObjectBaseImpl::reset(unsigned int vptrIndex, unsigned int vtblIndex)
+{
+ ChainableMockMethodIndexKey* key = \
+ new ChainableMockMethodIndexKey(vptrIndex, vtblIndex);
+ container->reset(key);
+}
////////////////////////////////////////////////////////////////////////
ChainableMockMethodCore*
MockObjectBaseImpl::getMethod(const std::string& name, void* addr, \
@@ -177,6 +185,14 @@
This->vtbl->setDestructor(vptrIndex, vtblIndex);
}
+////////////////////////////////////////////////////////////////////////
+void MockObjectBase::
+resetVirtualMethod(unsigned int vptrIndex, unsigned int vtblIndex)
+{
+ This->vtbl->reset(vptrIndex, vtblIndex);
+ This->reset(vptrIndex, vtblIndex);
+}
+
////////////////////////////////////////////////////////////////////////
void MockObjectBase::expectsBeingDeleted()
{
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -103,6 +103,12 @@
typedef T ParaType;
};
+template <typename Predict, typename T>
+struct PredictTypeTraits<bool (Predict::*)(T) const>
+{
+ typedef T ParaType;
+};
+
template <typename Predict>
Constraint* checkWith(Predict pred)
{
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -30,6 +30,7 @@
////////////////////////////////////////////////
JmpCodeImpl(const void* from, const void* to)
{
+ m_from = from;
::memcpy(m_code, jmpCodeTemplate, JMP_CODE_SIZE);
SET_JMP_CODE(m_code, from, to);
}
@@ -46,9 +47,14 @@
return JMP_CODE_SIZE;
}
+ void flushCache() const
+ {
+ FLUSH_CACHE(m_from, JMP_CODE_SIZE);
+ }
////////////////////////////////////////////////
unsigned char m_code[JMP_CODE_SIZE];
+ const void* m_from;
};
///////////////////////////////////////////////////
@@ -77,5 +83,11 @@
return This->getCodeSize();
}
+void
+ JmpCode::flushCache() const
+{
+ This->flushCache();
+}
+
MOCKCPP_NS_END
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -27,5 +27,7 @@
*(uintptr_t *)(base + 6) = (uintptr_t)to; \
} while(0)
+#define FLUSH_CACHE(from, length) do {} while (0)
+
#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -38,20 +38,40 @@
# define MOCKCPP_EXPORT
#endif
+#if defined(__aarch64__)
+
+#define BUILD_FOR_AARCH64
-#if ( defined (__LP64__) \
+#elif defined(__arm__)
+#include <cstdint>
+#define BUILD_FOR_AARCH32
+
+/*
+ * 参考《DDI0406C_d_armv7ar_arm.pdf》 A4.1 About the instruction sets
+ * armv7总共有4中指令集:
+ * thumb指令集: 主要指令集, 16bit/32bit, 能够自由的和arm指令集切换。
+ * arm指令集: 主要指令集, 32bit, 能够自由的和thumb指令集切换。
+ * thumbee: thumb的变种,用于动态代码生成,不能与thumb和arm自由切换。
+ * Jazelle: 扩展指令, 使得arm处理器能够直接执行一些java字节码。
+ *
+ * 此处只适配了主流的thumb和arm指令集。
+ * 参考A2.3.1 Writing to the PC 和 https://stackoverflow.com/questions/37004954/function-address-in-arm-assembly-have-one-byte-offset
+ * 在仅考虑arm和thumb指令集的前提下, 区分这两种指令集的方式是:thumb指令集下, 函数指针地址是奇数, arm指令集下函数指针地址是偶数。
+ */
+#define IS_USE_THUMB_INST_SET(ptr) (((uintptr_t)(ptr) % 2) != 0)
+#define CONVERT_THUMB_INST_SET_FUNC_POINTER(ptr) ((void *)((uintptr_t)ptr - 1))
+
+#elif ( defined (__LP64__) \
|| defined (__64BIT__) \
|| defined (_LP64) \
|| ((defined(__WORDSIZE)) && (__WORDSIZE == 64)) \
|| defined(WIN64))
-#define BUILD_FOR_X64 1
-#define BUILD_FOR_X86 0
+#define BUILD_FOR_X64
#else
-#define BUILD_FOR_X64 0
-#define BUILD_FOR_X86 1
+#define BUILD_FOR_X86
#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -33,6 +33,7 @@
void* getCodeData() const;
size_t getCodeSize() const;
+ void flushCache() const;
private:
JmpCodeImpl* This;
};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -44,6 +44,7 @@
getMethod(const void* api);
void reset();
+ void reset(const void* api);
ChainableMockMethodContainer* container;
@@ -64,6 +65,13 @@
container->reset();
}
+void
+HookMockObjectImpl::reset(const void *api)
+{
+ ApiHookKey key(api);
+ container->reset(&key);
+}
+
//////////////////////////////////////////////////////////////
ChainableMockMethodCore*
HookMockObjectImpl::
@@ -144,6 +152,11 @@
This->reset();
}
+void HookMockObject::reset(const void* api)
+{
+ This->reset(api);
+}
+
//////////////////////////////////////////////////////////////
MOCKCPP_NS_END
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -46,6 +46,7 @@
virtual ~Base(){}
virtual int method1(int a) { return 0; }
int method2(float b) { return 1; }
+ virtual int method3(int a) = 0;
int member;
int member2;
int member3;
@@ -55,6 +56,7 @@
public:
virtual ~Derived(){}
virtual int method1(int a) { return 10; }
+ virtual int method3(int a) { return 20; }
};
FIXTURE(mockcpp_sample, mockcpp samples)
@@ -86,6 +88,50 @@
ASSERT_EQ(1000, Interface::func());
GlobalMockObject::verify();
}
+
+ TEST(can reset specified static function)
+ {
+ MockObject<Interface> mocker;
+ MOCK_METHOD(mocker, method)
+ .stubs()
+ .will(returnValue(10));
+ MOCKER(Interface::func)
+ .stubs()
+ .will(returnValue(20));
+ ASSERT_EQ(10, mocker->method());
+ ASSERT_EQ(20, Interface::func());
+ GlobalMockObject::reset((const void *)Interface::func);
+ ASSERT_EQ(10, mocker->method());
+ ASSERT_EQ(0, Interface::func());
+ MOCKER(Interface::func)
+ .stubs()
+ .will(returnValue(200));
+ ASSERT_EQ(10, mocker->method());
+ ASSERT_EQ(200, Interface::func());
+ GlobalMockObject::verify();
+ }
+
+ TEST(can reset specified pure virtual function)
+ {
+ MockObject<Interface> mocker;
+ MOCK_METHOD(mocker, method)
+ .stubs()
+ .will(returnValue(10));
+ MOCKER(Interface::func)
+ .stubs()
+ .will(returnValue(20));
+ ASSERT_EQ(10, mocker->method());
+ ASSERT_EQ(20, Interface::func());
+ mocker.reset(&Interface::method);
+ ASSERT_THROWS_ANYTHING(mocker->method());
+ ASSERT_EQ(20, Interface::func());
+ MOCK_METHOD(mocker, method)
+ .stubs()
+ .will(returnValue(100));
+ ASSERT_EQ(100, mocker->method());
+ ASSERT_EQ(20, Interface::func());
+ GlobalMockObject::verify();
+ }
// mock的类不全是虚方法, 如果调用到非虚方法,则mock框架不会报错,而是调用真正的非虚方法,可能出现内存非法访问。
// 从设计解耦的角度讲,应尽可能面向接口编程,而需要mock的也都是接口。接口里面的方法全是虚方法。所以不存在这种情况。
@@ -111,6 +157,50 @@
ASSERT_EQ(8, sizeof(void*));
}
+ TEST(can reset specified virtual function in same mock object)
+ {
+ MockObject<Derived> mocker;
+ MOCK_METHOD(mocker, method1)
+ .stubs()
+ .will(returnValue(100));
+ MOCK_METHOD(mocker, method3)
+ .stubs()
+ .will(returnValue(200));
+ ASSERT_EQ(100, mocker->method1(10));
+ ASSERT_EQ(200, mocker->method3(10));
+ mocker.reset(&Derived::method1);
+ ASSERT_THROWS_ANYTHING(mocker->method1(10));
+ ASSERT_EQ(200, mocker->method3(10));
+ MOCK_METHOD(mocker, method1)
+ .stubs()
+ .will(returnValue(1000));
+ ASSERT_EQ(1000, mocker->method1(10));
+ ASSERT_EQ(200, mocker->method3(10));
+ GlobalMockObject::verify();
+ }
+
+ TEST(can reset specified pure virtual function in same mock object)
+ {
+ MockObject<Derived> mocker;
+ MOCK_METHOD(mocker, method1)
+ .stubs()
+ .will(returnValue(100));
+ MOCK_METHOD(mocker, method3)
+ .stubs()
+ .will(returnValue(200));
+ ASSERT_EQ(100, mocker->method1(10));
+ ASSERT_EQ(200, mocker->method3(10));
+ mocker.reset(&Derived::method3);
+ ASSERT_EQ(100, mocker->method1(10));
+ ASSERT_THROWS_ANYTHING(mocker->method3(10));
+ MOCK_METHOD(mocker, method3)
+ .stubs()
+ .will(returnValue(2000));
+ ASSERT_EQ(100, mocker->method1(10));
+ ASSERT_EQ(2000, mocker->method3(10));
+ GlobalMockObject::verify();
+ }
+
#if 0
// if not use MOCKCPP_USE_MOCKABLE, compile error
// if use MOCKCPP_USE_MOCKABLE, compile pass, but maybe all the MOCKER tests failed.
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -209,8 +209,9 @@
mock.method(&Interface::base00).expects(once()).will(returnValue(20));
TS_ASSERT_EQUALS(20, mock->base00());
+ mock->base00();
- TS_ASSERT_THROWS(mock->base00(), Exception);
+ TS_ASSERT_THROWS(mock.verify(), Exception);
}
// once()
@@ -232,6 +233,7 @@
TS_ASSERT_EQUALS(20, mock->base00());
TS_ASSERT_EQUALS(20, mock->base00());
+ TS_ASSERT_THROWS_NOTHING(mock.verify());
}
// exactly()
@@ -271,6 +273,7 @@
TS_ASSERT_EQUALS(20, mock->base00());
TS_ASSERT_EQUALS(20, mock->base00());
TS_ASSERT_EQUALS(20, mock->base00());
+ TS_ASSERT_THROWS_NOTHING(mock.verify());
}
// atLeast()
@@ -294,6 +297,7 @@
TS_ASSERT_EQUALS(20, mock->base00());
TS_ASSERT_EQUALS(20, mock->base00());
+ TS_ASSERT_THROWS_NOTHING(mock.verify());
}
// atMost()
@@ -304,6 +308,7 @@
mock.method(&Interface::base00).expects(atMost(2)).will(returnValue(20));
TS_ASSERT_EQUALS(20, mock->base00());
+ TS_ASSERT_THROWS_NOTHING(mock.verify());
}
// atMost()
@@ -311,11 +316,13 @@
{
MockObject<Interface> mock;
- mock.method(&Interface::base00).expects(atMost(2)).will(returnValue(20));
+ mock.method(&Interface::base00).expects(atMost(1)).will(returnValue(20));
TS_ASSERT_EQUALS(20, mock->base00());
TS_ASSERT_EQUALS(20, mock->base00());
- TS_ASSERT_THROWS(((Interface*)mock)->base00(), Exception);
+ TS_ASSERT_EQUALS(20, mock->base00());
+
+ TS_ASSERT_THROWS(mock.verify(), Exception);
}
// never()
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -32,7 +32,11 @@
, const void* stub)
: m_jmpCode(api, stub)
, m_originalData(0)
- , m_api(api)
+#ifndef __arm__
+ , m_api(api)
+#else
+ , m_api(IS_USE_THUMB_INST_SET(api) ? CONVERT_THUMB_INST_SET_FUNC_POINTER(api) : api)
+#endif
{
startHook();
}
@@ -68,6 +72,7 @@
void changeCode(const void* data)
{
CodeModifier::modify(const_cast<void*>(m_api), data, m_jmpCode.getCodeSize());
+ m_jmpCode.flushCache();
}
/////////////////////////////////////////////////////
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -39,8 +39,8 @@
};
/////////////////////////////////////////////////////////////////
-ApiHook::ApiHook
- ( const void* api
+ApiHook::ApiHook
+ ( const void* api
, const void* stub )
: This(new ApiHookImpl(api, stub))
{
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -40,6 +40,7 @@
InvocationMocker* findInvocationMocker(const std::string& id) const;
void reset();
+ void reset(ChainableMockMethodKey* key);
void verify();
private:
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -30,10 +30,12 @@
TESTCPP_VERIFY_RESOURCE_CHECK_POINT(checkpoint);
}
+#ifndef __clang__
void testShouldBeAbleCalculateNumberOfVptr_SingleInheritance()
{
TS_ASSERT_EQUALS(1, getNumberOfVtbls<Derived0>());
}
+#endif
struct Derived2 : public Base0, public Base1 {};
@@ -50,18 +52,20 @@
TS_ASSERT_EQUALS(sizeof(Derived4)/sizeof(void*), getNumberOfVtbls<Derived4>());
}
+#ifndef __clang__
struct Derived5 : public Derived2, public Derived0 {};
void testShouldBeAbleToCalculateTheNumberOfVptr_DupInheritance()
{
TS_ASSERT_EQUALS(sizeof(Derived5)/sizeof(void*), getNumberOfVtbls<Derived5>());
}
+#endif
+#if !(defined(_MSC_VER) || defined(__clang__))
struct Derived6 : virtual public Derived2, virtual public Derived0 {};
void testShouldBeThrowExcpetion_VirtualInheritance()
{
- #ifndef _MSC_VER
- //VC does not support
+ //VC does not support
TS_ASSERT_THROWS(getNumberOfVtbls<Derived6>(), MOCKCPP_NS::Exception);
- #endif
- }
+ }
+#endif
};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -47,7 +47,10 @@
TestMockcppSample.h
TestApiHookBase.h
TestSmartPointerChecker.h
+ TestOutBoundP.h
MockMethodSamples.h
+ TestMockClassPublic.h
+ TestMockMutlThread.h
)
IF(UNIX)
@@ -97,6 +100,7 @@
ELSE(MSVC)
ADD_DEFINITIONS(-std=c++14)
ENDIF(MSVC)
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pmf-conversions")
IF(UNIX OR MINGW)
ADD_DEFINITIONS(
@@ -134,7 +138,8 @@
TARGET_LINK_LIBRARIES(${CASE_MODULE}
testngpp-static
- mockcpp)
+ mockcpp
+ pthread)
ADD_CUSTOM_COMMAND(
OUTPUT ${CASE_SRC}
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -126,6 +126,8 @@
TS_ASSERT(getDeltaOfMethod(&Interface::base00) != getDeltaOfMethod(&Interface::base10));
}
+// 在arm64平台下虚函数和普通函数的 m.desc.u.index 都是偶数,在 GnuMethodInfoReader.h 中做的特殊处理对此测试例不生效
+#ifndef __aarch64__
void testShouldThrowAnExceptionIfTryToGetVtblIndexOfANonVirtualMethod()
{
TS_ASSERT_THROWS(getIndexOfMethod(&Interface::c), MOCKCPP_NS::Exception);
@@ -140,5 +142,6 @@
{
TS_ASSERT_THROWS(MOCKCPP_NS::getAddrOfMethod(&Interface::base00), MOCKCPP_NS::Exception);
}
+#endif
};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -54,6 +54,7 @@
FakeObject* fakeObject;
void** vtbl;
+ void** vtblBak;
unsigned int numberOfVptr;
IndexInvokableGetter* indexInvokableGetter;
ObjectNameGetter* nameGetter;
@@ -208,6 +209,8 @@
initializeVtbls(vptr, vtbl, numberOfVptr,refTypeInfo, true);
+ vtblBak = createVtbls(numberOfVptr);
+
vptr[MOCKCPP_MAX_INHERITANCE] = (void*)this;
deleted = false;
@@ -228,6 +231,12 @@
freeVtbls(vtbl, numberOfVptr);
vtbl = 0;
}
+
+ if (vtblBak != nullptr)
+ {
+ freeVtbls(vtblBak, numberOfVptr);
+ vtblBak = nullptr;
+ }
}
/////////////////////////////////////////////////////////////////
@@ -255,12 +264,15 @@
}
/////////////////////////////////////////////////////////////////
-void
-VirtualTable::addMethod(void* methodAddr, unsigned int indexOfVtbl, unsigned int indexOfVptr)
+void VirtualTable::
+addMethod(void* methodAddr, unsigned int indexOfVtbl, unsigned int indexOfVptr)
{
This->validateIndexOfVtbl(indexOfVtbl);
This->validateIndexOfVptr(indexOfVptr);
+ if (This->vtblBak[getRealVtblIndex(indexOfVptr, indexOfVtbl)] == nullptr)
+ This->vtblBak[getRealVtblIndex(indexOfVptr, indexOfVtbl)] =
+ This->vtbl[getRealVtblIndex(indexOfVptr, indexOfVtbl)];
This->vtbl[getRealVtblIndex(indexOfVptr, indexOfVtbl)] = methodAddr;
}
@@ -322,6 +334,18 @@
This->reset();
}
+void
+VirtualTable::reset(unsigned int vptrIndex, unsigned int vtblIndex)
+{
+ if (This->vtblBak[getRealVtblIndex(vptrIndex, vtblIndex)] == nullptr)
+ return;
+ This->validateIndexOfVptr(vptrIndex);
+ This->validateIndexOfVtbl(vtblIndex);
+ This->vtbl[getRealVtblIndex(vptrIndex, vtblIndex)] =
+ This->vtblBak[getRealVtblIndex(vptrIndex, vtblIndex)];
+ This->vtblBak[getRealVtblIndex(vptrIndex, vtblIndex)] = nullptr;
+}
+
/////////////////////////////////////////////////////////////////
void
VirtualTable::verify()
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -39,6 +39,16 @@
return 0;
}
+int bar(void)
+{
+ return 0;
+}
+
+int baz(int a, int b)
+{
+ return 0;
+}
+
FIXTURE(ApiHook)
{
int a; //TODO: static const cause linux .so load failure.
@@ -90,10 +100,70 @@
ASSERT_EQ(20, func2(500));
}
- TEST(can mock 2 functions which has same prototype)
- {
- MOCKER(foo).stubs().will(returnValue(20));
- ASSERT_EQ(ret, func(a, b));
- ASSERT_EQ(20, foo(a, b));
- }
+ TEST(can mock 2 functions which has same prototype)
+ {
+ MOCKER(foo).stubs().will(returnValue(20));
+ ASSERT_EQ(ret, func(a, b));
+ ASSERT_EQ(20, foo(a, b));
+ }
+
+ TEST(can reset specified function for different prototype 1)
+ {
+ func(a, b);
+ MOCKER(foo).stubs().will(returnValue(10));
+ MOCKER(bar).stubs().will(returnValue(20));
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(20, bar());
+ GlobalMockObject::reset((const void *)foo);
+ ASSERT_EQ(0, foo(a, b));
+ ASSERT_EQ(20, bar());
+ MOCKER(foo).stubs().will(returnValue(100));
+ ASSERT_EQ(100, foo(a, b));
+ ASSERT_EQ(20, bar());
+ }
+
+ TEST(can reset specified function for different prototype 2)
+ {
+ func(a, b);
+ MOCKER(foo).stubs().will(returnValue(10));
+ MOCKER(bar).stubs().will(returnValue(20));
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(20, bar());
+ GlobalMockObject::reset((const void *)bar);
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(0, bar());
+ MOCKER(bar).stubs().will(returnValue(200));
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(200, bar());
+ }
+
+ TEST(can reset specified function for same prototype 1)
+ {
+ func(a, b);
+ MOCKER(foo).stubs().will(returnValue(10));
+ MOCKER(baz).stubs().will(returnValue(20));
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(20, baz(a, b));
+ GlobalMockObject::reset((const void *)foo);
+ ASSERT_EQ(0, foo(a, b));
+ ASSERT_EQ(20, baz(a, b));
+ MOCKER(foo).stubs().will(returnValue(100));
+ ASSERT_EQ(100, foo(a, b));
+ ASSERT_EQ(20, baz(a, b));
+ }
+
+ TEST(can reset specified function for same prototype 2)
+ {
+ func(a, b);
+ MOCKER(foo).stubs().will(returnValue(10));
+ MOCKER(baz).stubs().will(returnValue(20));
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(20, baz(a, b));
+ GlobalMockObject::reset((const void *)baz);
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(0, baz(a, b));
+ MOCKER(baz).stubs().will(returnValue(200));
+ ASSERT_EQ(10, foo(a, b));
+ ASSERT_EQ(200, baz(a, b));
+ }
};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -54,6 +54,7 @@
#include <mem_checker/reporter.h>
#include <mem_checker/format.h>
#include <mem_checker/check_status.h>
+#include <mutex>
@@ -260,12 +261,12 @@
/**
* The mutex guard to protect simultaneous access to the pointer list.
*/
-static fast_mutex new_ptr_lock;
+static std::mutex new_ptr_lock;
/**
* The mutex guard to protect simultaneous output to #new_output_fp.
*/
-static fast_mutex new_output_lock;
+static std::mutex new_output_lock;
/**
* Total memory allocated in bytes.
@@ -507,7 +508,7 @@
#if _DEBUG_NEW_STD_OPER_NEW
return NULL;
#else
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
#ifndef USED_IN_XUNIT
fprintf(new_output_fp,
"Out of memory when allocating %u bytes\n",
@@ -538,7 +539,7 @@
ptr->magic = MAGIC;
ptr->check_status = getCheckStatus();
{
- fast_mutex_autolock lock(new_ptr_lock);
+ std::lock_guard<std::mutex> lock_ptr(new_ptr_lock);
ptr->prev = new_ptr_list.prev;
ptr->next = &new_ptr_list;
new_ptr_list.prev->next = ptr;
@@ -550,7 +551,7 @@
#endif
if (new_verbose_flag)
{
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
fprintf(new_output_fp,
"new%s: allocated %p (size %lu, ",
is_array ? "[]" : "",
@@ -583,7 +584,7 @@
if (ptr->magic != MAGIC)
{
{
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
#ifndef USED_IN_XUNIT
fprintf(new_output_fp, "delete%s: invalid pointer %p (",
is_array ? "[]" : "", pointer);
@@ -611,7 +612,7 @@
msg = "delete[] after new";
else
msg = "delete after new[]";
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
#ifndef USED_IN_XUNIT
fprintf(new_output_fp,
"%s: pointer %p (%u bytes)\n\tat ",
@@ -648,7 +649,7 @@
}
#endif
{
- fast_mutex_autolock lock(new_ptr_lock);
+ std::lock_guard<std::mutex> lock_ptr(new_ptr_lock);
total_mem_alloc -= ptr->size;
ptr->magic = 0;
ptr->prev->next = ptr->next;
@@ -656,7 +657,7 @@
}
if (new_verbose_flag)
{
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
fprintf(new_output_fp,
"delete%s: freed %p (size %lu, %lu bytes still allocated)\n",
is_array ? "[]" : "",
@@ -686,7 +687,7 @@
void clear_all_allocate_info()
{
- fast_mutex_autolock lock_ptr(new_ptr_lock);
+ std::lock_guard<std::mutex> lock_ptr(new_ptr_lock);
new_ptr_list_t* ptr = new_ptr_list.next;
while (ptr != &new_ptr_list)
{
@@ -706,8 +707,8 @@
{
int leak_cnt = 0;
unsigned int print_count_this_time = 0;
- fast_mutex_autolock lock_ptr(new_ptr_lock);
- fast_mutex_autolock lock_output(new_output_lock);
+ std::lock_guard<std::mutex> lock_ptr(new_ptr_lock);
+ std::lock_guard<std::mutex> lock_output(new_output_lock);
new_ptr_list_t* ptr = new_ptr_list.next;
while (ptr != &new_ptr_list)
{
@@ -784,8 +785,8 @@
int check_mem_corruption()
{
int corrupt_cnt = 0;
- fast_mutex_autolock lock_ptr(new_ptr_lock);
- fast_mutex_autolock lock_output(new_output_lock);
+ std::lock_guard<std::mutex> lock_ptr(new_ptr_lock);
+ std::lock_guard<std::mutex> lock_output(new_output_lock);
fprintf(new_output_fp, "*** Checking for memory corruption: START\n");
for (new_ptr_list_t* ptr = new_ptr_list.next;
ptr != &new_ptr_list;
@@ -839,7 +840,7 @@
(new_ptr_list_t*)((char*)pointer - ALIGNED_LIST_ITEM_SIZE);
if (ptr->magic != MAGIC || ptr->line != 0)
{
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
get_info_reporter()->report(
_M_file, _M_line,
"warning: debug_new used with placement new."
@@ -917,7 +918,7 @@
{
if (new_verbose_flag)
{
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
fprintf(new_output_fp,
"info: exception thrown on initializing object at %p (",
pointer);
@@ -931,7 +932,7 @@
{
if (new_verbose_flag)
{
- fast_mutex_autolock lock(new_output_lock);
+ std::lock_guard<std::mutex> lock(new_output_lock);
fprintf(new_output_fp,
"info: exception thrown on initializing objects at %p (",
pointer);
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -52,6 +52,7 @@
void* toPointerToInterface() const;
void setDestructor(unsigned int vptrIndex, unsigned int vtblIndex);
+ void resetVirtualMethod(unsigned int vptrIndex, unsigned int vtblIndex);
void expectsBeingDeleted();
void expectsKeepAlive();
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -36,13 +36,6 @@
///////////////////////////////////////////////////////
void InvokedAtMost::increaseInvoked(const Invocation& inv)
{
- oss_t oss;
-
- oss << "Expected at most " << highLimit
- << " times, but you are trying to invoke more than that.";
-
- MOCKCPP_ASSERT_TRUE_MESSAGE(
- oss.str(), getInvokedTimes() < highLimit);
}
///////////////////////////////////////////////////////
@@ -58,17 +51,14 @@
///////////////////////////////////////////////////////
void InvokedAtMost::verify(void)
{
-// We won't need to verify it here, it was checked at runtime.
-#if 0
oss_t oss;
-
- oss << "Expected at most " << highLimit
+
+ oss << "Expected at most " << highLimit
<< " times, but it's actually invoked " << getInvokedTimes() << " times";
MOCKCPP_ASSERT_TRUE_MESSAGE(
oss.str(),
getInvokedTimes() <= highLimit);
-#endif
}
MOCKCPP_NS_END
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -123,6 +123,14 @@
MockObjectBase::reset();
identifyDestructor<Interface, Interface>();
}
+
+ template <typename Method>
+ void reset(Method m)
+ {
+ std::pair<unsigned int, unsigned int> indices = \
+ getIndicesOfMethod<Interface, Method>(m);
+ resetVirtualMethod(indices.first, indices.second);
+ }
/////////////////////////////////////////////////////////////
template <typename Method>
InvocationMockBuilderGetter method(Method m, const char* name = 0)
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -301,12 +301,15 @@
TS_ASSERT_EQUALS(expected, toTypeAndValueString(c));
}
+// 在arm64平台下-1的返回值是 (std::string)"(char)0xff/255" 与期望值 (std::string)"(char)0xff/-1" 不符
+#ifndef __aarch64__
void testShouldBeAbleToStringnizeNegativeChar()
{
char c = -1;
std::string expected("(char)0xff/-1");
TS_ASSERT_EQUALS(expected, toTypeAndValueString(c));
}
+#endif
void testShouldBeAbleToStringnizeShort()
{
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -139,5 +139,34 @@
ASSERT_EQ(10, input.a);
}
+
+ TEST(Can check with mutable lambda)
+ {
+ MOCK_METHOD(mocker, method)
+ .expects(once())
+ .with(checkWith([](STRUCT_T *p) mutable {
+ p->a = 10;
+ return p->b == 2;
+ }));
+
+ client(mocker, &input);
+
+ ASSERT_EQ(10, input.a);
+ }
+
+ TEST(Can check with immutable lambda)
+ {
+ MOCK_METHOD(mocker, method)
+ .expects(once())
+ .with(checkWith([](STRUCT_T *p) {
+ p->a = 10;
+ return p->b == 2;
+ }));
+
+ client(mocker, &input);
+
+ ASSERT_EQ(10, input.a);
+ }
+
};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -35,14 +35,6 @@
///////////////////////////////////////////////////////
void InvokedOnce::increaseInvoked(const Invocation& inv)
{
- oss_t oss;
-
- oss << "Invocation is expected only once(), but you are trying to "
- << "invoke more than that";
-
- MOCKCPP_ASSERT_TRUE_MESSAGE(
- oss.str(), getInvokedTimes() < 1);
-
}
///////////////////////////////////////////////////////
std::string
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -23,5 +23,7 @@
(unsigned long long)to - (unsigned long long)from - sizeof(jmpCodeTemplate); \
} while(0)
+#define FLUSH_CACHE(from, length) do {} while (0)
+
#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -32,6 +32,7 @@
}
};
+#if !(defined(__aarch64__) && defined(__clang__))
TEST(static member function mocker test)
{
MOCKER(CUT::func)
@@ -40,4 +41,5 @@
ASSERT_EQ(100, CUT::func());
GlobalMockObject::verify();
}
+#endif
};
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
new file mode 100644
@@ -0,0 +1,82 @@
+
+#ifndef __MOCKCPP_JMP_CODE_AARCH64_H__
+#define __MOCKCPP_JMP_CODE_AARCH64_H__
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+MOCKCPP_NS_START
+
+struct l2cache_addr_range {
+ uintptr_t start;
+ uintptr_t end;
+};
+
+MOCKCPP_NS_END
+
+#define ADDR_ALIGN_UP(addr) ((((addr) + ((4096) - 1)) & (~((4096) - 1))) & 0xffffffffffffffff)
+#define ADDR_ALIGN_DOWN(addr) (((addr) & (~((4096) - 1))) & 0xffffffffffffffff)
+
+const unsigned char jmpCodeTemplate[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
+#define ARM_BYTE_ORDER(x) ((x & 0xff) << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24)
+// br x9 跳转到桩函数,执行后直接从桩函数返回,回到`x30`存储的位置。因为在这`5`条指令中未修改`x30`,所以回到了调用者函数的位置
+const uint32_t jump_code = ARM_BYTE_ORDER(0x20011fd6);
+
+static inline uint32_t get_mov_xn_code(uintptr_t val, uint32_t reg_id)
+{
+ uint32_t code = 0xd2800000; // mov 指令是 11010010 100 + 16bit val + 5bit reg id
+ val = (val & 0xffff) << 5;
+ code |= (uint32_t)val;
+ reg_id &= 0x1f;
+ code |= reg_id;
+ return code;
+}
+
+static inline uint32_t get_movk_xn_code(uintptr_t val, uint32_t pos, uint32_t reg_id)
+{
+ uint32_t code = 0xf2800000; // movk 指令是 11110010 1 + 2bit offset + 16bit val + 5bit reg id
+ pos &= 0x3;
+ val = ((val >> (16 * pos)) & 0xffff) << 5;
+ code |= (uint32_t)val;
+ pos = pos << 21;
+ code |= pos;
+ reg_id &= 0x1f;
+ code |= reg_id;
+ return code;
+}
+
+#define SET_JMP_CODE(base, from, to) do { \
+ uint32_t reg = 9; \
+ uint32_t d_index = 0; \
+ uint32_t *d_ptr = (uint32_t *)base; \
+ d_ptr[d_index++] = get_mov_xn_code((uintptr_t)to, reg); \
+ d_ptr[d_index++] = get_movk_xn_code((uintptr_t)to, 1, reg); \
+ d_ptr[d_index++] = get_movk_xn_code((uintptr_t)to, 2, reg); \
+ d_ptr[d_index++] = get_movk_xn_code((uintptr_t)to, 3, reg); \
+ d_ptr[d_index++] = jump_code; \
+} while (0)
+
+#ifdef __GNUC__
+#define FLUSH_CACHE(from, length) do { \
+ struct l2cache_addr_range usr_data; \
+ usr_data.start = ADDR_ALIGN_DOWN((unsigned long long)from); \
+ usr_data.end = ADDR_ALIGN_UP((unsigned long long)from) + length; \
+ __builtin___clear_cache((char *)usr_data.start, (char *)usr_data.end); \
+} while (0)
+#else
+#define FLUSH_CACHE(from, length) do {} while (0)
+#endif
+
+#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
new file mode 100644
@@ -0,0 +1,158 @@
+
+#ifndef __MOCKCPP_JMP_CODE_AARCH32_H__
+#define __MOCKCPP_JMP_CODE_AARCH32_H__
+
+#include <mockcpp/mockcpp.h>
+
+MOCKCPP_NS_START
+
+struct l2cache_addr_range {
+ uintptr_t start;
+ uintptr_t end;
+};
+
+MOCKCPP_NS_END
+
+#define ADDR_ALIGN_UP(addr) ((((addr) + ((4096) - 1)) & (~((4096) - 1))) & 0xffffffff)
+#define ADDR_ALIGN_DOWN(addr) (((addr) & (~((4096) - 1))) & 0xffffffff)
+
+#define IS_USE_THUMB_INST_SET(ptr) (((uintptr_t)(ptr) % 2) != 0)
+#define CONVERT_THUMB_INST_SET_FUNC_POINTER(ptr) ((void *)((uintptr_t)ptr - 1))
+
+/*
+ * 参考 《DDI0406C_d_armv7ar_arm.pdf》 A8.8.103 MOV (immediate)
+ * thumb MOVW encoding T3的编码方式如下:
+ * 11110 i 100100 imm4 0 imm3 Rd imm8
+ * arm MOVW encoding A2的编码方式如下:
+ * cond 00110000 imm4 Rd imm12
+ */
+static uint32_t get_thumb_movw_imme_code(uint8_t reg_id, uint16_t imme)
+{
+ uint32_t code = 0xf2400000;
+ code |= ((reg_id & 0xff) << 8);
+ code |= (((imme & 0xf000) >> 12) << 16);
+ code |= ((((imme & 0x0f00) >> 8) & 0b0111) << 12);
+ code |= (((((imme & 0x0f00) >> 8) & 0b1000) >> 3) << 26);
+ code |= ((imme & 0x00ff));
+ return code;
+}
+
+static uint32_t get_arm32_movw_imme_code(uint8_t reg_id, uint16_t imme)
+{
+ uint32_t code = 0xE3000000;
+ code |= ((reg_id & 0xff) << 12);
+ code |= (((imme & 0xf000) >> 12) << 16);
+ code |= (imme & 0x0fff);
+ return code;
+}
+
+/*
+ * 参考 《DDI0406C_d_armv7ar_arm.pdf》 A8.8.107 MOVT
+ * thumb MOVT encoding T1的编码方式如下:
+ * 11110 i 101100 imm4 0 imm3 Rd imm8
+ * arm MOVT encoding A1的编码方式如下:
+ * cond 00110100 imm4 Rd imm12
+ */
+static uint32_t get_thumb_movt_imme_code(uint8_t reg_id, uint16_t imme)
+{
+ uint32_t code = 0xf2c00000;
+ code |= ((reg_id & 0xff) << 8);
+ code |= (((imme & 0xf000) >> 12) << 16);
+ code |= ((((imme & 0x0f00) >> 8) & 0b0111) << 12);
+ code |= (((((imme & 0x0f00) >> 8) & 0b1000) >> 3) << 26);
+ code |= ((imme & 0x00ff));
+ return code;
+}
+
+static uint32_t get_arm32_movt_imme_code(uint8_t reg_id, uint16_t imme)
+{
+ uint32_t code = 0xE3400000;
+ code |= ((reg_id & 0xff) << 12);
+ code |= (((imme & 0xf000) >> 12) << 16);
+ code |= (imme & 0x0fff);
+ return code;
+}
+
+/*
+ * 参考 《DDI0406C_d_armv7ar_arm.pdf》 A8.8.27 BX
+ * thumb BX encoding T1的编码方式如下:
+ * 010001110 Rm 000
+ * arm BX encoding A1的编码方式如下:
+ * cond 00010010111111111111 +0001 Rm
+ */
+static uint16_t get_thumb_bx_code(uint8_t reg_id)
+{
+ uint16_t code = 0x4700;
+ code |= (reg_id & 0xff) << 3;
+ return code;
+}
+
+static uint32_t get_arm32_bx_code(uint8_t reg_id)
+{
+ uint32_t code = 0xE12FFF10;
+ code |= (reg_id & 0xff);
+ return code;
+}
+
+/*
+ * 不改变任何寄存器和栈空间的跳转指令组合:
+ *
+ * thumb模式下的跳转指令需要6条指令22个字节, arm32模式下的跳转指令需要6条指令24个字节:
+ * sub sp, #8 # 申请8 bytes的栈空间
+ * str.w r9, [sp] # 将R9保存在栈顶向下的4 bytes(32位中)
+ * mov.w r9, stub_addr_low #
+ * movt r9, stub_addr_high # 将stub_addr保存在r9寄存器中
+ * str.w r9, [sp, #4] # 将R9保存在剩下的4 bytes(32位中)栈空间中
+ * pop {r9, pc} # 将栈内的8bytes弹出, 同时赋值给r9和pc寄存器
+ */
+
+static constexpr uint16_t SUB_SP_8_THUMB_CODE = 0xB082;
+static constexpr uint32_t STR_R9_SP_THUMB_CODE = 0xF8CD9000;
+static constexpr uint32_t STR_R9_SP_4_THUMB_CODE = 0xF8CD9004;
+static constexpr uint32_t POP_R9_PC_THUMB_CODE = 0xE8BD8200;
+
+static constexpr uint32_t SUB_SP_8_ARM_CODE = 0xE24DD008;
+static constexpr uint32_t STR_R9_SP_ARM_CODE = 0xE58D9000;
+static constexpr uint32_t STR_R9_SP_4_ARM_CODE = 0xE58D9004;
+static constexpr uint32_t POP_R9_PC_ARM_CODE = 0xE8BD8200;
+
+const unsigned char jmpCodeTemplate[24] = { 0 };
+#define SET_JMP_CODE(base, from, to) do { \
+ uint32_t stub_addr = (uint32_t)to; \
+ char *target_addr = (char *)base; \
+ if (IS_USE_THUMB_INST_SET(from)) { \
+ uint32_t thumbMovwCode = get_thumb_movw_imme_code(9, (stub_addr & 0xffff)); \
+ uint32_t thumbMovtCode = get_thumb_movt_imme_code(9, (stub_addr >> 16)); \
+ ((uint16_t*)target_addr)[0] = SUB_SP_8_THUMB_CODE; \
+ ((uint16_t*)target_addr)[1] = (STR_R9_SP_THUMB_CODE >> 16); \
+ ((uint16_t*)target_addr)[2] = (STR_R9_SP_THUMB_CODE & 0xffff); \
+ ((uint16_t*)target_addr)[3] = (thumbMovwCode >> 16); \
+ ((uint16_t*)target_addr)[4] = (thumbMovwCode & 0xffff); \
+ ((uint16_t*)target_addr)[5] = (thumbMovtCode >> 16); \
+ ((uint16_t*)target_addr)[6] = (thumbMovtCode & 0xffff); \
+ ((uint16_t*)target_addr)[7] = (STR_R9_SP_4_THUMB_CODE >> 16); \
+ ((uint16_t*)target_addr)[8] = (STR_R9_SP_4_THUMB_CODE & 0xffff); \
+ ((uint16_t*)target_addr)[9] = (POP_R9_PC_THUMB_CODE >> 16); \
+ ((uint16_t*)target_addr)[10] = (POP_R9_PC_THUMB_CODE & 0xffff); \
+ } else { \
+ ((uint32_t*)target_addr)[0] = SUB_SP_8_ARM_CODE; \
+ ((uint32_t*)target_addr)[1] = STR_R9_SP_ARM_CODE; \
+ ((uint32_t*)target_addr)[2] = get_arm32_movw_imme_code(9, (stub_addr & 0xffff)); \
+ ((uint32_t*)target_addr)[3] = get_arm32_movt_imme_code(9, (stub_addr >> 16)); \
+ ((uint32_t*)target_addr)[4] = STR_R9_SP_4_ARM_CODE; \
+ ((uint32_t*)target_addr)[5] = POP_R9_PC_ARM_CODE; \
+ } \
+} while(0)
+
+#ifdef __GNUC__
+#define FLUSH_CACHE(from, length) do { \
+ struct l2cache_addr_range usr_data; \
+ usr_data.start = ADDR_ALIGN_DOWN((unsigned long long)from); \
+ usr_data.end = ADDR_ALIGN_UP((unsigned long long)from) + length; \
+ __builtin___clear_cache((char *)usr_data.start, (char *)usr_data.end); \
+} while (0)
+#else
+#define FLUSH_CACHE(from, length) do {} while (0)
+#endif
+
+#endif
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
@@ -38,6 +38,7 @@
{
static void verify();
static void reset();
+ static void reset(const void* api);
static MockObjectType instance;
};