mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2024-12-04 16:24:16 +01:00
1231 lines
36 KiB
C++
1231 lines
36 KiB
C++
|
#include <string>
|
||
|
#include "sourcehook.h"
|
||
|
#include "sourcehook_test.h"
|
||
|
#include "testevents.h"
|
||
|
#include "sh_memory.h"
|
||
|
#include "sh_pagealloc.h"
|
||
|
#include "sourcehook_pibuilder.h"
|
||
|
|
||
|
// TESTHOOKMANGEN
|
||
|
// Test automatic hookman generation
|
||
|
// Tests void and non-void functions
|
||
|
// 0 to 6 params:
|
||
|
// integer-type, float-type, plain-old-data struct and objects with ctors/dtors
|
||
|
// both byval and byref
|
||
|
// also tests ignore/supercede
|
||
|
// also tests recalls
|
||
|
|
||
|
// :TODO: test override as well
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
StateList g_States;
|
||
|
SourceHook::ISourceHook *g_SHPtr;
|
||
|
SourceHook::Plugin g_PLID;
|
||
|
|
||
|
SourceHook::IHookManagerAutoGen *g_HMAGPtr;
|
||
|
|
||
|
// PtrBuf(ptr) gives ptrs unique numbers
|
||
|
// in the order they appear
|
||
|
SourceHook::List<const void*> g_PtrHash;
|
||
|
|
||
|
bool g_Inside_LeafFunc = false; // inside a hook or a func
|
||
|
bool g_Silent_CtorDtor = false; // inside a hook or a func
|
||
|
|
||
|
|
||
|
// POD / Object types
|
||
|
template <int MYSIZE>
|
||
|
struct POD
|
||
|
{
|
||
|
char x[MYSIZE];
|
||
|
|
||
|
bool operator==(const POD<MYSIZE> &other)
|
||
|
{
|
||
|
return memcmp(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE) == 0;
|
||
|
}
|
||
|
|
||
|
bool operator==(char other)
|
||
|
{
|
||
|
for (int i = 0; i < MYSIZE; ++i)
|
||
|
{
|
||
|
if (x[i] != other)
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <int MYSIZE>
|
||
|
std::ostream& operator <<(std::ostream &os, const POD<MYSIZE> &obj)
|
||
|
{
|
||
|
os << "Some POD!";
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
MAKE_STATE_1(State_ObjOCtor_Called, int /*MYSIZE*/);
|
||
|
MAKE_STATE_1(State_ObjCCtor_Called, int /*MYSIZE*/);
|
||
|
MAKE_STATE_1(State_ObjODtor_Called, int /*MYSIZE*/);
|
||
|
MAKE_STATE_1(State_ObjAssignOp_Called, int /*MYSIZE*/);
|
||
|
|
||
|
template <int MYSIZE>
|
||
|
struct Object
|
||
|
{
|
||
|
char x[MYSIZE];
|
||
|
|
||
|
Object(char initch)
|
||
|
{
|
||
|
memset(reinterpret_cast<void*>(x), initch, MYSIZE);
|
||
|
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
|
||
|
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
|
||
|
}
|
||
|
|
||
|
Object()
|
||
|
{
|
||
|
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
|
||
|
ADD_STATE(State_ObjOCtor_Called(MYSIZE));
|
||
|
}
|
||
|
|
||
|
Object(const Object<MYSIZE> & other)
|
||
|
{
|
||
|
memcpy(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE);
|
||
|
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
|
||
|
ADD_STATE(State_ObjCCtor_Called(MYSIZE));
|
||
|
}
|
||
|
|
||
|
~Object()
|
||
|
{
|
||
|
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
|
||
|
ADD_STATE(State_ObjODtor_Called(MYSIZE));
|
||
|
}
|
||
|
|
||
|
Object & operator = (const Object &other)
|
||
|
{
|
||
|
if (!g_Inside_LeafFunc && !g_Silent_CtorDtor)
|
||
|
ADD_STATE(State_ObjAssignOp_Called(MYSIZE));
|
||
|
|
||
|
memcpy(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
bool operator==(const Object<MYSIZE> &other)
|
||
|
{
|
||
|
return memcmp(reinterpret_cast<void*>(x), reinterpret_cast<const void*>(other.x), MYSIZE) == 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <int MYSIZE>
|
||
|
std::ostream& operator <<(std::ostream &os, const Object<MYSIZE> &obj)
|
||
|
{
|
||
|
os << "Some Obj" << static_cast<int>(obj.x[0]);
|
||
|
return os;
|
||
|
}
|
||
|
|
||
|
// Because of some weird bug in MSVC < 1400
|
||
|
#define MAKE_PODRET(size) \
|
||
|
struct PodRet##size \
|
||
|
{ \
|
||
|
POD<size> actPod; \
|
||
|
bool operator==(const PodRet##size &other) { return actPod == other.actPod; } \
|
||
|
bool operator==(char other) { return actPod == other; } \
|
||
|
}; \
|
||
|
std::ostream& operator <<(std::ostream &os, const PodRet##size &obj) \
|
||
|
{ \
|
||
|
os << obj.actPod; \
|
||
|
return os; \
|
||
|
} \
|
||
|
template <> struct MakeRet< PodRet##size > \
|
||
|
{ \
|
||
|
static PodRet##size Do(int a) \
|
||
|
{ \
|
||
|
PodRet##size x; \
|
||
|
memset(reinterpret_cast<void*>(x.actPod.x), a, size); \
|
||
|
return x; \
|
||
|
} \
|
||
|
};
|
||
|
|
||
|
#define MAKE_OBJRET(size) \
|
||
|
struct ObjRet##size \
|
||
|
{ \
|
||
|
Object<size> actObj; \
|
||
|
bool operator==(const ObjRet##size &other) { return actObj == other.actObj; } \
|
||
|
bool operator==(char other) { return actObj == other; } \
|
||
|
}; \
|
||
|
std::ostream& operator <<(std::ostream &os, const ObjRet##size &obj) \
|
||
|
{ \
|
||
|
os << obj.actObj; \
|
||
|
return os; \
|
||
|
} \
|
||
|
template <> struct MakeRet< ObjRet##size > \
|
||
|
{ \
|
||
|
static ObjRet##size Do(int a) NO_OPTIMIZE \
|
||
|
{ \
|
||
|
ObjRet##size *x = new ObjRet##size; /* ptr: otherwise gcc optimizes away the temp obj */ \
|
||
|
CAutoPtrDestruction< ObjRet##size > apd(x); \
|
||
|
memset(reinterpret_cast<void*>(x->actObj.x), a, size); \
|
||
|
return *x; \
|
||
|
} \
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// "Increment" something: (reproducible change for recall tests)
|
||
|
// integer: ++
|
||
|
// float: += 1.3
|
||
|
// pod/object: x[i]++, 0 <= i < MYSIZE
|
||
|
template <class T>
|
||
|
struct Increment
|
||
|
{
|
||
|
static void Incr(T &what)
|
||
|
{
|
||
|
++what;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct Increment<float>
|
||
|
{
|
||
|
static void Incr(float &what)
|
||
|
{
|
||
|
what += 1.3f;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct Increment<double>
|
||
|
{
|
||
|
static void Incr(double &what)
|
||
|
{
|
||
|
what += 1.3;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<int MYSIZE>
|
||
|
struct Increment< POD<MYSIZE> >
|
||
|
{
|
||
|
static void Incr(POD<MYSIZE> &what)
|
||
|
{
|
||
|
for (int i = 0; i < MYSIZE; ++i)
|
||
|
++ what.x[i];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<int MYSIZE>
|
||
|
struct Increment< Object<MYSIZE> >
|
||
|
{
|
||
|
static void Incr(Object<MYSIZE> &what)
|
||
|
{
|
||
|
for (int i = 0; i < MYSIZE; ++i)
|
||
|
++ what.x[i];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct Increment<std::string>
|
||
|
{
|
||
|
static void Incr(std::string &what)
|
||
|
{
|
||
|
what += "!";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#include "testhookmangen.h"
|
||
|
|
||
|
template <class T>
|
||
|
int PtrBuf(T ptr)
|
||
|
{
|
||
|
int a = 0;
|
||
|
|
||
|
const void *vptr = reinterpret_cast<const void*>(ptr);
|
||
|
for (SourceHook::List<const void*>::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end(); ++iter)
|
||
|
{
|
||
|
if (*iter == vptr)
|
||
|
return a;
|
||
|
else
|
||
|
++a;
|
||
|
}
|
||
|
g_PtrHash.push_back(vptr);
|
||
|
return static_cast<int>(g_PtrHash.size()) - 1;
|
||
|
}
|
||
|
|
||
|
template <class T>
|
||
|
T PtrBufPtr(T ptr)
|
||
|
{
|
||
|
PtrBuf(ptr);
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
void PtrBuf_Clear(int leave_in = 0)
|
||
|
{
|
||
|
for (SourceHook::List<const void*>::iterator iter = g_PtrHash.begin(); iter != g_PtrHash.end();)
|
||
|
{
|
||
|
if (--leave_in < 0)
|
||
|
iter = g_PtrHash.erase(iter);
|
||
|
else
|
||
|
++iter;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// MyDelegate base class for other delegates
|
||
|
class MyDelegate : public SourceHook::ISHDelegate
|
||
|
{
|
||
|
// Unneeded
|
||
|
// because we don't use old SH_REMOVE_HOOK syntax
|
||
|
virtual bool IsEqual(SourceHook::ISHDelegate *pOtherDeleg)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
virtual void DeleteThis()
|
||
|
{
|
||
|
delete this;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
THGM_MAKE_TEST0_void(0);
|
||
|
THGM_SETUP_PI0(0);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(1, char);
|
||
|
THGM_SETUP_PI1(1, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(2, short);
|
||
|
THGM_SETUP_PI1(2, short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(3, int);
|
||
|
THGM_SETUP_PI1(3, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(4, float);
|
||
|
THGM_SETUP_PI1(4, float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(5, double);
|
||
|
THGM_SETUP_PI1(5, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST5_void(6, char, short, int, float, double);
|
||
|
THGM_SETUP_PI5(6,
|
||
|
char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
|
||
|
THGM_MAKE_TEST2_void(7, char&, double&);
|
||
|
THGM_SETUP_PI2(7,
|
||
|
char&, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByRef,
|
||
|
double&, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByRef
|
||
|
);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(8, POD<7>);
|
||
|
THGM_SETUP_PI1(8, POD<7>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(9, POD<600>);
|
||
|
THGM_SETUP_PI1(9, POD<600>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_void(10, POD<600> &);
|
||
|
THGM_SETUP_PI1(10, POD<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef);
|
||
|
|
||
|
THGM_MAKE_TEST2_void(11, Object<3>, Object<600>&);
|
||
|
THGM_SETUP_PI2(11,
|
||
|
Object<3>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor,
|
||
|
Object<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor | SourceHook::PassInfo::PassFlag_CCtor
|
||
|
);
|
||
|
|
||
|
THGM_MAKE_TEST0(101, char);
|
||
|
THGM_SETUP_PI0(101);
|
||
|
THGM_SETUP_RI(101, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST0(102, short);
|
||
|
THGM_SETUP_PI0(102);
|
||
|
THGM_SETUP_RI(102, short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST0(103, int);
|
||
|
THGM_SETUP_PI0(103);
|
||
|
THGM_SETUP_RI(103, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST0(104, float);
|
||
|
THGM_SETUP_PI0(104);
|
||
|
THGM_SETUP_RI(104, float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST0(105, double);
|
||
|
THGM_SETUP_PI0(105);
|
||
|
THGM_SETUP_RI(105, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
// pod 1-13
|
||
|
MAKE_PODRET(1);
|
||
|
THGM_MAKE_TEST1(106, PodRet1, int);
|
||
|
THGM_SETUP_PI1(106,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(106, PodRet1, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
MAKE_PODRET(4);
|
||
|
THGM_MAKE_TEST1(107, PodRet4, int);
|
||
|
THGM_SETUP_PI1(107,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(107, PodRet4, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
MAKE_PODRET(8);
|
||
|
THGM_MAKE_TEST1(108, PodRet8, int);
|
||
|
THGM_SETUP_PI1(108,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(108, PodRet8, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
MAKE_PODRET(13);
|
||
|
THGM_MAKE_TEST1(109, PodRet13, int);
|
||
|
THGM_SETUP_PI1(109,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(109, PodRet13, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
MAKE_OBJRET(13);
|
||
|
THGM_MAKE_TEST1(110, ObjRet13, int);
|
||
|
THGM_SETUP_PI1(110,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(110, ObjRet13, SourceHook::PassInfo::PassType_Object,
|
||
|
SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor |
|
||
|
SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp);
|
||
|
|
||
|
MAKE_OBJRET(111);
|
||
|
ObjRet111 g_O111_0;
|
||
|
ObjRet111 g_O111_1;
|
||
|
ObjRet111 g_O111_2;
|
||
|
ObjRet111 g_O111_3;
|
||
|
ObjRet111 g_O111_4;
|
||
|
|
||
|
template <>
|
||
|
struct MakeRet< ObjRet111& >
|
||
|
{
|
||
|
static ObjRet111 &Do(int a)
|
||
|
{
|
||
|
switch (a)
|
||
|
{
|
||
|
case 0:
|
||
|
return g_O111_0;
|
||
|
case 1:
|
||
|
return g_O111_1;
|
||
|
case 2:
|
||
|
return g_O111_2;
|
||
|
case 3:
|
||
|
return g_O111_3;
|
||
|
default:
|
||
|
return g_O111_4;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
THGM_MAKE_TEST0(111, ObjRet111& );
|
||
|
THGM_SETUP_PI0(111);
|
||
|
THGM_SETUP_RI(111, ObjRet111& , SourceHook::PassInfo::PassType_Object,
|
||
|
SourceHook::PassInfo::PassFlag_ByRef | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor |
|
||
|
SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp);
|
||
|
|
||
|
|
||
|
THGM_MAKE_TEST3_void(150, int, double, int);
|
||
|
THGM_SETUP_PI3(150,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
// vafmt tests
|
||
|
THGM_MAKE_TEST0_vafmt_void(200);
|
||
|
THGM_SETUP_PI0(200);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt_void(201, char);
|
||
|
THGM_SETUP_PI1(201, char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt_void(203, int);
|
||
|
THGM_SETUP_PI1(203, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST5_vafmt_void(206, char, short, int, float, double);
|
||
|
THGM_SETUP_PI5(206,
|
||
|
char, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
short, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
float, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal,
|
||
|
double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
|
||
|
THGM_MAKE_TEST2_vafmt_void(207, char&, double&);
|
||
|
THGM_SETUP_PI2(207,
|
||
|
char&, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByRef,
|
||
|
double&, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByRef
|
||
|
);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt_void(208, POD<7>);
|
||
|
THGM_SETUP_PI1(208, POD<7>, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt_void(210, POD<600> &);
|
||
|
THGM_SETUP_PI1(210, POD<600> &, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByRef)
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt(211, int, int);
|
||
|
THGM_SETUP_PI1(211,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(211, int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt(212, double, int);
|
||
|
THGM_SETUP_PI1(212,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(212, double, SourceHook::PassInfo::PassType_Float, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt(213, PodRet8, int);
|
||
|
THGM_SETUP_PI1(213,
|
||
|
int, SourceHook::PassInfo::PassType_Basic, SourceHook::PassInfo::PassFlag_ByVal
|
||
|
);
|
||
|
THGM_SETUP_RI(213, PodRet8, SourceHook::PassInfo::PassType_Object, SourceHook::PassInfo::PassFlag_ByVal);
|
||
|
|
||
|
THGM_MAKE_TEST1_vafmt_void(214, Object<133>);
|
||
|
THGM_SETUP_PI1(214, Object<133>, SourceHook::PassInfo::PassType_Object,
|
||
|
SourceHook::PassInfo::PassFlag_ByVal | SourceHook::PassInfo::PassFlag_OCtor | SourceHook::PassInfo::PassFlag_ODtor |
|
||
|
SourceHook::PassInfo::PassFlag_CCtor | SourceHook::PassInfo::PassFlag_AssignOp);
|
||
|
|
||
|
|
||
|
MAKE_STATE(State_Hello_Func4_Called);
|
||
|
MAKE_STATE(State_Hello_Func79_Called);
|
||
|
|
||
|
MAKE_STATE(State_Hello_Func4_PreHook);
|
||
|
MAKE_STATE(State_Hello_Func79_PreHook);
|
||
|
|
||
|
// Test for larger vtable indices
|
||
|
class Hello
|
||
|
{
|
||
|
public:
|
||
|
virtual void Func0() {}
|
||
|
virtual void Func1() {}
|
||
|
virtual void Func2() {}
|
||
|
virtual void Func3() {}
|
||
|
virtual void Func4()
|
||
|
{
|
||
|
ADD_STATE(State_Hello_Func4_Called);
|
||
|
}
|
||
|
virtual void Func5() {}
|
||
|
virtual void Func6() {}
|
||
|
virtual void Func7() {}
|
||
|
virtual void Func8() {}
|
||
|
virtual void Func9() {}
|
||
|
virtual void Func10() {}
|
||
|
virtual void Func11() {}
|
||
|
virtual void Func12() {}
|
||
|
virtual void Func13() {}
|
||
|
virtual void Func14() {}
|
||
|
virtual void Func15() {}
|
||
|
virtual void Func16() {}
|
||
|
virtual void Func17() {}
|
||
|
virtual void Func18() {}
|
||
|
virtual void Func19() {}
|
||
|
virtual void Func20() {}
|
||
|
virtual void Func21() {}
|
||
|
virtual void Func22() {}
|
||
|
virtual void Func23() {}
|
||
|
virtual void Func24() {}
|
||
|
virtual void Func25() {}
|
||
|
virtual void Func26() {}
|
||
|
virtual void Func27() {}
|
||
|
virtual void Func28() {}
|
||
|
virtual void Func29() {}
|
||
|
virtual void Func30() {}
|
||
|
virtual void Func31() {}
|
||
|
virtual void Func32() {}
|
||
|
virtual void Func33() {}
|
||
|
virtual void Func34() {}
|
||
|
virtual void Func35() {}
|
||
|
virtual void Func36() {}
|
||
|
virtual void Func37() {}
|
||
|
virtual void Func38() {}
|
||
|
virtual void Func39() {}
|
||
|
virtual void Func40() {}
|
||
|
virtual void Func41() {}
|
||
|
virtual void Func42() {}
|
||
|
virtual void Func43() {}
|
||
|
virtual void Func44() {}
|
||
|
virtual void Func45() {}
|
||
|
virtual void Func46() {}
|
||
|
virtual void Func47() {}
|
||
|
virtual void Func48() {}
|
||
|
virtual void Func49() {}
|
||
|
virtual void Func50() {}
|
||
|
virtual void Func51() {}
|
||
|
virtual void Func52() {}
|
||
|
virtual void Func53() {}
|
||
|
virtual void Func54() {}
|
||
|
virtual void Func55() {}
|
||
|
virtual void Func56() {}
|
||
|
virtual void Func57() {}
|
||
|
virtual void Func58() {}
|
||
|
virtual void Func59() {}
|
||
|
virtual void Func60() {}
|
||
|
virtual void Func61() {}
|
||
|
virtual void Func62() {}
|
||
|
virtual void Func63() {}
|
||
|
virtual void Func64() {}
|
||
|
virtual void Func65() {}
|
||
|
virtual void Func66() {}
|
||
|
virtual void Func67() {}
|
||
|
virtual void Func68() {}
|
||
|
virtual void Func69() {}
|
||
|
virtual void Func70() {}
|
||
|
virtual void Func71() {}
|
||
|
virtual void Func72() {}
|
||
|
virtual void Func73() {}
|
||
|
virtual void Func74() {}
|
||
|
virtual void Func75() {}
|
||
|
virtual void Func76() {}
|
||
|
virtual void Func77() {}
|
||
|
virtual void Func78() {}
|
||
|
virtual void Func79()
|
||
|
{
|
||
|
ADD_STATE(State_Hello_Func79_Called);
|
||
|
}
|
||
|
};
|
||
|
class Hello_Func4_Deleg : public MyDelegate
|
||
|
{
|
||
|
virtual void Func()
|
||
|
{
|
||
|
ADD_STATE(State_Hello_Func4_PreHook);
|
||
|
}
|
||
|
};
|
||
|
class Hello_Func79_Deleg : public MyDelegate
|
||
|
{
|
||
|
int a;
|
||
|
virtual void Func()
|
||
|
{
|
||
|
ADD_STATE(State_Hello_Func79_PreHook);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
bool Tests1(std::string &error)
|
||
|
{
|
||
|
THGM_DO_TEST_void(0, ());
|
||
|
|
||
|
THGM_DO_TEST_void(1, (100));
|
||
|
|
||
|
THGM_DO_TEST_void(2, (0x1F00));
|
||
|
|
||
|
THGM_DO_TEST_void(3, (0x1F000000));
|
||
|
|
||
|
THGM_DO_TEST_void(4, (0.5f));
|
||
|
|
||
|
THGM_DO_TEST_void(5, (5.5));
|
||
|
|
||
|
THGM_DO_TEST_void(6, (100, 0x1f00, 0x1f000000, 0.5f, 5.5));
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Tests2(std::string &error)
|
||
|
{
|
||
|
char a = 5;
|
||
|
double b = 233.33;
|
||
|
THGM_DO_TEST_void(7, (a, b));
|
||
|
|
||
|
POD<7> pod7 = MakeRet< POD<7> >::Do(78);
|
||
|
THGM_DO_TEST_void(8, (pod7));
|
||
|
|
||
|
POD<600> pod600 = MakeRet< POD<600> >::Do(34);
|
||
|
THGM_DO_TEST_void(9, (pod600));
|
||
|
|
||
|
THGM_DO_TEST_void(10, (pod600));
|
||
|
|
||
|
// Test11: Special: constructors/destructors
|
||
|
PtrBuf_Clear();
|
||
|
Object<3> *obj3_real = new Object<3>(33);
|
||
|
Object<600> *obj600_real = new Object<600>(21);
|
||
|
|
||
|
Object<3> & obj3 = *obj3_real;
|
||
|
Object<600> & obj600 = *obj600_real;
|
||
|
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjOCtor_Called(3),
|
||
|
new State_ObjOCtor_Called(600),
|
||
|
NULL), "Test11 Part0");
|
||
|
|
||
|
setuppi_11();
|
||
|
SourceHook::HookManagerPubFunc myhookman11 = g_HMAGPtr->MakeHookMan(protoinfo_11, 0, 0); \
|
||
|
CAutoReleaseHookMan arhm_11(myhookman11); \
|
||
|
int hook1_11, hook2_11, hook3_11, hook4_11;
|
||
|
|
||
|
TestClass11 *pTest11 = new TestClass11;
|
||
|
CAutoPtrDestruction<TestClass11> apd11(pTest11);
|
||
|
|
||
|
/* no hooks - no hooks */
|
||
|
PtrBuf_Clear();
|
||
|
pTest11->Func(obj3, obj600);
|
||
|
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
NULL), "Test" "11" " Part1");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
/* hook1 - no hooks */
|
||
|
THGM_ADD_HOOK(11, 1);
|
||
|
|
||
|
PtrBuf_Clear();
|
||
|
pTest11->Func(obj3, obj600);
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(1, pTest11, 0, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
new State_ObjODtor_Called(3),
|
||
|
NULL), "Test" "11" " Part2");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
THGM_REMOVE_HOOK(11, 1);
|
||
|
|
||
|
/* hook1, hook2 - hook3, hook4 */
|
||
|
THGM_ADD_HOOK(11, 1);
|
||
|
THGM_ADD_HOOK(11, 2);
|
||
|
THGM_ADD_HOOK(11, 3);
|
||
|
THGM_ADD_HOOK(11, 4);
|
||
|
PtrBuf_Clear();
|
||
|
pTest11->Func(obj3, obj600);
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(1, pTest11, 0, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(2, pTest11, 1, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(3, pTest11, 2, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(4, pTest11, 3, ParamState_m11 (obj3, obj600)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
new State_ObjODtor_Called(3),
|
||
|
NULL), "Test" "11" " Part3");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
/* hook1 - hook3, hook4 WITH RECALLS */
|
||
|
THGM_REMOVE_HOOK(11, 2);
|
||
|
PtrBuf_Clear();
|
||
|
TestClass11::ms_DoRecall = true;
|
||
|
pTest11->Func(obj3, obj600);
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(1, pTest11, 0 /* first deleg ptr */, ParamState_m11 (obj3, obj600)),
|
||
|
|
||
|
// recall !
|
||
|
// second hookfunc -> new copy
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
|
||
|
// in second hookfunc now
|
||
|
// -> calls orig func
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Func11(pTest11, ParamState_m11 (obj3, obj600)(1)),
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
// calls first posthook
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(3, pTest11, 1 /* second deleg ptr */, ParamState_m11 (obj3, obj600)(1)),
|
||
|
|
||
|
// recall!
|
||
|
// third hookfunc -> new copy
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
|
||
|
// calls second posthook
|
||
|
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
new State_Deleg_11(4, pTest11, 2 /* third deleg ptr */, ParamState_m11 (obj3, obj600)(2)),
|
||
|
|
||
|
// recall!
|
||
|
// fourth hookfunc -> new copy
|
||
|
new State_ObjCCtor_Called(3),
|
||
|
|
||
|
// has nothing to do though!
|
||
|
|
||
|
// fourth hookfunc done -> ret
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
// third hookfunc done -> ret
|
||
|
new State_ObjODtor_Called(3),
|
||
|
// ret from hookhandler which did the recall
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
// second hookfunc done -> ret
|
||
|
new State_ObjODtor_Called(3),
|
||
|
// ret from hookhandler which did the recall
|
||
|
new State_ObjODtor_Called(3),
|
||
|
|
||
|
// deleg1's instance
|
||
|
new State_ObjODtor_Called(3),
|
||
|
// first hookfunc done -> ret
|
||
|
new State_ObjODtor_Called(3),
|
||
|
NULL), "Test" "11" " Part4");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
THGM_REMOVE_HOOK(11, 1);
|
||
|
THGM_REMOVE_HOOK(11, 3);
|
||
|
THGM_REMOVE_HOOK(11, 4);
|
||
|
|
||
|
delete obj3_real;
|
||
|
delete obj600_real;
|
||
|
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjODtor_Called(3),
|
||
|
new State_ObjODtor_Called(600),
|
||
|
NULL), "Test11 Part100");
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Tests3(std::string &error)
|
||
|
{
|
||
|
THGM_DO_TEST(101, ());
|
||
|
|
||
|
THGM_DO_TEST(102, ());
|
||
|
|
||
|
THGM_DO_TEST(103, ());
|
||
|
|
||
|
THGM_DO_TEST(104, ());
|
||
|
|
||
|
THGM_DO_TEST(105, ());
|
||
|
|
||
|
// pod returns
|
||
|
THGM_DO_TEST(106, (5));
|
||
|
THGM_DO_TEST(107, (5));
|
||
|
THGM_DO_TEST(108, (5));
|
||
|
THGM_DO_TEST(109, (5));
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Tests4(std::string &error)
|
||
|
{
|
||
|
// Test110: Special: constructors/destructors on return
|
||
|
PtrBuf_Clear();
|
||
|
ObjRet13 *obj13_real = new ObjRet13;
|
||
|
ObjRet13 &obj13 = *obj13_real;
|
||
|
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
NULL), "Test110 Part0");
|
||
|
|
||
|
setuppi_110();
|
||
|
setupri_110();
|
||
|
|
||
|
SourceHook::HookManagerPubFunc myhookman110 = g_HMAGPtr->MakeHookMan(protoinfo_110, 0, 0); \
|
||
|
CAutoReleaseHookMan arhm_110(myhookman110); \
|
||
|
int hook1_110, hook2_110, hook3_110, hook4_110;
|
||
|
|
||
|
TestClass110 *pTest110 = new TestClass110;
|
||
|
CAutoPtrDestruction<TestClass110> apd110(pTest110);
|
||
|
|
||
|
/* no hooks - no hooks */
|
||
|
PtrBuf_Clear();
|
||
|
obj13 = pTest110->Func(5);
|
||
|
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_Func110(pTest110, ParamState_m110 (5)),
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in our stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
new State_ObjAssignOp_Called(13), // assign: obj13 = temporary object in our stack
|
||
|
new State_ObjODtor_Called(13), // Func110: destruction of temporary object
|
||
|
NULL), "Test" "110" " Part1");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
/* hook1 - no hooks */
|
||
|
THGM_ADD_HOOK(110, 1);
|
||
|
|
||
|
PtrBuf_Clear();
|
||
|
obj13 = pTest110->Func(5);
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
// HookFunc: construct orig_ret/override_ret/plugin_ret objects
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
|
||
|
// Calling delegate
|
||
|
new State_Deleg_110(1, pTest110, 0, ParamState_m110 (5)),
|
||
|
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
// back in hookfunc
|
||
|
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
|
||
|
|
||
|
// Calling orig function Func110
|
||
|
new State_Func110(pTest110, ParamState_m110 (5)),
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
// back in hookfunc
|
||
|
new State_ObjAssignOp_Called(13), // assign: orig_ret = temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
|
||
|
|
||
|
// hookfunc is returning:
|
||
|
new State_ObjCCtor_Called(13), // copy to temp object in our stack
|
||
|
|
||
|
// hookfunc cleans up its stack -> destroys plugin_ret/override_ret/orig_ret
|
||
|
new State_ObjODtor_Called(13),
|
||
|
new State_ObjODtor_Called(13),
|
||
|
new State_ObjODtor_Called(13),
|
||
|
|
||
|
// we are in our function: assign
|
||
|
new State_ObjAssignOp_Called(13), // assign: obj13 = temporary object in our stack
|
||
|
new State_ObjODtor_Called(13), // Func110: destruction of temporary object
|
||
|
|
||
|
NULL), "Test" "11" " Part2");
|
||
|
|
||
|
CHECK_COND(obj13 == 0, "Test" "11" " Part 2.1");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
THGM_REMOVE_HOOK(110, 1);
|
||
|
|
||
|
/* hook1, hook2 - hook3, hook4 */
|
||
|
THGM_ADD_HOOK(110, 1);
|
||
|
THGM_ADD_HOOK(110, 2);
|
||
|
THGM_ADD_HOOK(110, 3);
|
||
|
THGM_ADD_HOOK(110, 4);
|
||
|
|
||
|
PtrBuf_Clear();
|
||
|
obj13 = pTest110->Func(5);
|
||
|
g_Inside_LeafFunc = true;
|
||
|
CHECK_STATES((&g_States,
|
||
|
// HookFunc: construct orig_ret/override_ret/plugin_ret objects
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
new State_ObjOCtor_Called(13),
|
||
|
|
||
|
// Calling delegate1
|
||
|
new State_Deleg_110(1, pTest110, 0, ParamState_m110 (5)),
|
||
|
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
// back in hookfunc
|
||
|
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
|
||
|
|
||
|
|
||
|
// Calling delegate2
|
||
|
new State_Deleg_110(2, pTest110, 1, ParamState_m110 (5)),
|
||
|
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
// back in hookfunc
|
||
|
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
|
||
|
|
||
|
// hookfunc finds out that the hook wanted to SUPERCEDE --> copy to override_Ret
|
||
|
new State_ObjAssignOp_Called(13),
|
||
|
|
||
|
// SUPERCEDE -> orig function is not called
|
||
|
// instead: orig_ret = override_ret
|
||
|
new State_ObjAssignOp_Called(13),
|
||
|
|
||
|
// Calling delegate3
|
||
|
new State_Deleg_110(3, pTest110, 2, ParamState_m110 (5)),
|
||
|
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
// back in hookfunc
|
||
|
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
|
||
|
|
||
|
// Calling delegate4
|
||
|
new State_Deleg_110(4, pTest110, 3, ParamState_m110 (5)),
|
||
|
|
||
|
new State_ObjOCtor_Called(13), // MakeRet: Construction of x
|
||
|
new State_ObjCCtor_Called(13), // Return from MakeRet -> construct temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // MakeRet: Destruction of x
|
||
|
|
||
|
// back in hookfunc
|
||
|
new State_ObjAssignOp_Called(13), // assign: plugin_ret = temporary object in HookFunc's stack
|
||
|
new State_ObjODtor_Called(13), // destruction of temporary object in HookFunc's stack
|
||
|
|
||
|
// hookfunc finds out that the hook wanted to SUPERCEDE --> copy to override_Ret (yes really, we overwrite the old value!)
|
||
|
new State_ObjAssignOp_Called(13),
|
||
|
|
||
|
// hookfunc is returning:
|
||
|
new State_ObjCCtor_Called(13), // copy to temp object in our stack
|
||
|
|
||
|
// hookfunc cleans up its stack -> destroys plugin_ret/override_ret/orig_ret
|
||
|
new State_ObjODtor_Called(13),
|
||
|
new State_ObjODtor_Called(13),
|
||
|
new State_ObjODtor_Called(13),
|
||
|
|
||
|
// we are in our function: assign
|
||
|
new State_ObjAssignOp_Called(13), // assign: obj13 = temporary object in our stack
|
||
|
new State_ObjODtor_Called(13), // Func110: destruction of temporary object
|
||
|
|
||
|
NULL), "Test" "11" " Part3");
|
||
|
|
||
|
CHECK_COND(obj13 == 4, "Test" "11" " Part 3.1");
|
||
|
g_Inside_LeafFunc = false;
|
||
|
|
||
|
THGM_REMOVE_HOOK(110, 1);
|
||
|
THGM_REMOVE_HOOK(110, 2);
|
||
|
THGM_REMOVE_HOOK(110, 3);
|
||
|
THGM_REMOVE_HOOK(110, 4);
|
||
|
|
||
|
delete obj13_real;
|
||
|
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjODtor_Called(13),
|
||
|
NULL), "Test110 Part100");
|
||
|
|
||
|
|
||
|
THGM_DO_TEST_void(150, (5, 5.5, 6));
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool Tests5(std::string &error)
|
||
|
{
|
||
|
// RefRet
|
||
|
THGM_DO_TEST(111, ());
|
||
|
|
||
|
// Vafmt
|
||
|
|
||
|
THGM_DO_TEST_void(200, ("Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
THGM_DO_TEST_void(201, (100, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
THGM_DO_TEST_void(203, (0x1F000000, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
THGM_DO_TEST_void(206, (100, 0x1f00, 0x1f000000, 0.5f, 5.5, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
char a = 5;
|
||
|
double b = 233.33;
|
||
|
THGM_DO_TEST_void(207, (a, b, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
POD<7> pod7 = MakeRet< POD<7> >::Do(78);
|
||
|
THGM_DO_TEST_void(208, (pod7, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
POD<600> pod600 = MakeRet< POD<600> >::Do(34);
|
||
|
THGM_DO_TEST_void(210, (pod600, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
|
||
|
THGM_DO_TEST(211, (5, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
THGM_DO_TEST(212, (5, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
THGM_DO_TEST(213, (5, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
|
||
|
// Silence Object's ctors/dtors: we only want a forced byref param
|
||
|
g_Silent_CtorDtor = true;
|
||
|
Object<133> *myobj133 = new Object<133>;
|
||
|
THGM_DO_TEST_void(214, (*myobj133, "Hello %s%d%s", "BA", 1, "L!"));
|
||
|
delete myobj133;
|
||
|
g_Silent_CtorDtor = false;
|
||
|
|
||
|
// Test for high vtable indices
|
||
|
Hello *pHello = new Hello;
|
||
|
CAutoPtrDestruction<Hello> apdHello(pHello);
|
||
|
SourceHook::CProtoInfoBuilder helloPi(SourceHook::ProtoInfo::CallConv_ThisCall);
|
||
|
SourceHook::HookManagerPubFunc helloHM_4 = g_HMAGPtr->MakeHookMan(helloPi, 0, 4);
|
||
|
SourceHook::HookManagerPubFunc helloHM_79 = g_HMAGPtr->MakeHookMan(helloPi, 0, 79);
|
||
|
|
||
|
pHello->Func4();
|
||
|
pHello->Func79();
|
||
|
SH_CALL(pHello, &Hello::Func4)();
|
||
|
SH_CALL(pHello, &Hello::Func79)();
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_Hello_Func4_Called,
|
||
|
new State_Hello_Func79_Called,
|
||
|
new State_Hello_Func4_Called,
|
||
|
new State_Hello_Func79_Called,
|
||
|
NULL), "Test" "Hello" " Part1");
|
||
|
|
||
|
int helloHook4 = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pHello),
|
||
|
0, helloHM_4, new Hello_Func4_Deleg, false);
|
||
|
|
||
|
int helloHook79 = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast<void*>(pHello),
|
||
|
0, helloHM_79, new Hello_Func79_Deleg, false);
|
||
|
|
||
|
pHello->Func4();
|
||
|
pHello->Func79();
|
||
|
SH_CALL(pHello, &Hello::Func4)();
|
||
|
SH_CALL(pHello, &Hello::Func79)();
|
||
|
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_Hello_Func4_PreHook,
|
||
|
new State_Hello_Func4_Called,
|
||
|
new State_Hello_Func79_PreHook,
|
||
|
new State_Hello_Func79_Called,
|
||
|
new State_Hello_Func4_Called,
|
||
|
new State_Hello_Func79_Called,
|
||
|
NULL), "Test" "Hello" " Part2");
|
||
|
|
||
|
g_SHPtr->RemoveHookByID(helloHook4);
|
||
|
g_SHPtr->RemoveHookByID(helloHook79);
|
||
|
|
||
|
g_HMAGPtr->ReleaseHookMan(helloHM_4);
|
||
|
g_HMAGPtr->ReleaseHookMan(helloHM_79);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool TestHookManGen(std::string &error)
|
||
|
{
|
||
|
GET_SHPTR(g_SHPtr);
|
||
|
GET_HMAG(g_HMAGPtr, g_SHPtr);
|
||
|
g_PLID = 1337;
|
||
|
|
||
|
// 5 Global constructors (g_O111_*)
|
||
|
CHECK_STATES((&g_States,
|
||
|
new State_ObjOCtor_Called(111),
|
||
|
new State_ObjOCtor_Called(111),
|
||
|
new State_ObjOCtor_Called(111),
|
||
|
new State_ObjOCtor_Called(111),
|
||
|
new State_ObjOCtor_Called(111),
|
||
|
NULL), "GlobCtors");
|
||
|
|
||
|
if (!Tests1(error))
|
||
|
return false;
|
||
|
if (!Tests2(error))
|
||
|
return false;
|
||
|
if (!Tests3(error))
|
||
|
return false;
|
||
|
if (!Tests4(error))
|
||
|
return false;
|
||
|
if (!Tests5(error))
|
||
|
return false;
|
||
|
|
||
|
// Shutdown now!
|
||
|
// If we don't SH will auto-shutdown _after_ genc's destructor is called
|
||
|
// -> crash
|
||
|
|
||
|
Test_CompleteShutdown(g_SHPtr);
|
||
|
|
||
|
CHECK_COND(sizeof(PodRet1) == 1, "WTF!");
|
||
|
CHECK_COND(sizeof(PodRet4) == 4, "WTF!");
|
||
|
CHECK_COND(sizeof(PodRet8) == 8, "WTF!");
|
||
|
CHECK_COND(sizeof(PodRet13) == 13, "WTF!");
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool TestCPageAlloc(std::string &error)
|
||
|
{
|
||
|
using namespace SourceHook;
|
||
|
|
||
|
CPageAlloc alloc;
|
||
|
int i;
|
||
|
size_t ps = alloc.GetPageSize();
|
||
|
|
||
|
char *test1[8];
|
||
|
|
||
|
for (i = 0; i < 8; ++i)
|
||
|
test1[i] = (char*) alloc.Alloc(ps / 4);
|
||
|
|
||
|
CHECK_COND(test1[1] == test1[0] + ps/4, "Part 1.1");
|
||
|
CHECK_COND(test1[2] == test1[1] + ps/4, "Part 1.2");
|
||
|
CHECK_COND(test1[3] == test1[2] + ps/4, "Part 1.3");
|
||
|
|
||
|
CHECK_COND(test1[5] == test1[4] + ps/4, "Part 1.4");
|
||
|
CHECK_COND(test1[6] == test1[5] + ps/4, "Part 1.5");
|
||
|
CHECK_COND(test1[7] == test1[6] + ps/4, "Part 1.6");
|
||
|
|
||
|
void *test2 = alloc.Alloc(ps * 3);
|
||
|
|
||
|
alloc.SetRW(test2);
|
||
|
memset(test2, 0, ps * 3); // should not crash :)
|
||
|
alloc.SetRE(test2);
|
||
|
|
||
|
alloc.Free(test2);
|
||
|
|
||
|
// Dealloc a ps/4 block and place two ps/8 blocks into it
|
||
|
alloc.Free(test1[2]);
|
||
|
|
||
|
char *test3[2];
|
||
|
test3[0] = (char*) alloc.Alloc(ps / 8);
|
||
|
test3[1] = (char*) alloc.Alloc(ps / 8);
|
||
|
|
||
|
CHECK_COND(test3[0] == test1[2], "Part 2.1");
|
||
|
CHECK_COND(test3[1] == test1[2] + ps/8, "Part 2.2");
|
||
|
|
||
|
// Isolated
|
||
|
char *test4[8];
|
||
|
for (i = 0; i < 8; ++i)
|
||
|
test4[i] = (char*) alloc.AllocIsolated(ps / 4);
|
||
|
|
||
|
// -> The difference is at least one page
|
||
|
CHECK_COND(static_cast<size_t>(abs(test4[1] - test4[0])) >= ps, "Part 3.1");
|
||
|
CHECK_COND(static_cast<size_t>(abs(test4[2] - test4[1])) >= ps, "Part 3.2");
|
||
|
CHECK_COND(static_cast<size_t>(abs(test4[3] - test4[2])) >= ps, "Part 3.3");
|
||
|
|
||
|
CHECK_COND(static_cast<size_t>(abs(test4[5] - test4[4])) >= ps, "Part 3.4");
|
||
|
CHECK_COND(static_cast<size_t>(abs(test4[6] - test4[5])) >= ps, "Part 3.5");
|
||
|
CHECK_COND(static_cast<size_t>(abs(test4[7] - test4[6])) >= ps, "Part 3.6");
|
||
|
|
||
|
// Thus i can set everything except for test4[2] to RE and still write to test4[2]
|
||
|
|
||
|
alloc.SetRW(test4[2]);
|
||
|
|
||
|
alloc.SetRE(test4[0]);
|
||
|
alloc.SetRE(test4[1]);
|
||
|
alloc.SetRE(test4[3]);
|
||
|
alloc.SetRE(test4[4]);
|
||
|
alloc.SetRE(test4[5]);
|
||
|
alloc.SetRE(test4[6]);
|
||
|
alloc.SetRE(test4[7]);
|
||
|
|
||
|
memset((void*)test4[2], 0, ps / 4);
|
||
|
|
||
|
// alignement tests
|
||
|
CPageAlloc alloc1(1);
|
||
|
CPageAlloc alloc4(4);
|
||
|
CPageAlloc alloc16(16);
|
||
|
|
||
|
void *last1 = alloc1.Alloc(1);
|
||
|
void *last4 = alloc4.Alloc(4);
|
||
|
void *last16 = alloc16.Alloc(16);
|
||
|
void *cur;
|
||
|
for (int i = 0; i < 20; ++i)
|
||
|
{
|
||
|
cur = alloc1.Alloc(1);
|
||
|
CHECK_COND(reinterpret_cast<intptr_t>(cur) == reinterpret_cast<intptr_t>(last1) + 1, "Part 4.1");
|
||
|
last1 = cur;
|
||
|
|
||
|
cur = alloc4.Alloc(1);
|
||
|
CHECK_COND(reinterpret_cast<intptr_t>(cur) == reinterpret_cast<intptr_t>(last4) + 4, "Part 4.2");
|
||
|
last4 = cur;
|
||
|
|
||
|
cur = alloc16.Alloc(1);
|
||
|
CHECK_COND(reinterpret_cast<intptr_t>(cur) == reinterpret_cast<intptr_t>(last16) + 16, "Part 4.3");
|
||
|
last16 = cur;
|
||
|
}
|
||
|
|
||
|
alloc16.Free(alloc16.Alloc(1));
|
||
|
return true;
|
||
|
}
|