#include #include #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 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 struct POD { char x[MYSIZE]; bool operator==(const POD &other) { return memcmp(reinterpret_cast(x), reinterpret_cast(other.x), MYSIZE) == 0; } bool operator==(char other) { for (int i = 0; i < MYSIZE; ++i) { if (x[i] != other) return false; } return true; } }; template std::ostream& operator <<(std::ostream &os, const POD &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 struct Object { char x[MYSIZE]; Object(char initch) { memset(reinterpret_cast(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 & other) { memcpy(reinterpret_cast(x), reinterpret_cast(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(x), reinterpret_cast(other.x), MYSIZE); return *this; } bool operator==(const Object &other) { return memcmp(reinterpret_cast(x), reinterpret_cast(other.x), MYSIZE) == 0; } }; template std::ostream& operator <<(std::ostream &os, const Object &obj) { os << "Some Obj" << static_cast(obj.x[0]); return os; } // Because of some weird bug in MSVC < 1400 #define MAKE_PODRET(size) \ struct PodRet##size \ { \ POD 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(x.actPod.x), a, size); \ return x; \ } \ }; #define MAKE_OBJRET(size) \ struct ObjRet##size \ { \ Object 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(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 struct Increment { static void Incr(T &what) { ++what; } }; template<> struct Increment { static void Incr(float &what) { what += 1.3f; } }; template<> struct Increment { static void Incr(double &what) { what += 1.3; } }; template struct Increment< POD > { static void Incr(POD &what) { for (int i = 0; i < MYSIZE; ++i) ++ what.x[i]; } }; template struct Increment< Object > { static void Incr(Object &what) { for (int i = 0; i < MYSIZE; ++i) ++ what.x[i]; } }; template<> struct Increment { static void Incr(std::string &what) { what += "!"; } }; #include "testhookmangen.h" template int PtrBuf(T ptr) { int a = 0; const void *vptr = reinterpret_cast(ptr); for (SourceHook::List::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(g_PtrHash.size()) - 1; } template T PtrBufPtr(T ptr) { PtrBuf(ptr); return ptr; } void PtrBuf_Clear(int leave_in = 0) { for (SourceHook::List::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 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 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 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(pHello), 0, helloHM_4, new Hello_Func4_Deleg, false); int helloHook79 = g_SHPtr->AddHook(g_PLID, SourceHook::ISourceHook::Hook_Normal, reinterpret_cast(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; } } #if !defined( _M_AMD64 ) && !defined( __amd64__ ) && !defined(__x86_64__) 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; } #endif 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(std::abs(test4[1] - test4[0])) >= ps, "Part 3.1"); CHECK_COND(static_cast(std::abs(test4[2] - test4[1])) >= ps, "Part 3.2"); CHECK_COND(static_cast(std::abs(test4[3] - test4[2])) >= ps, "Part 3.3"); CHECK_COND(static_cast(std::abs(test4[5] - test4[4])) >= ps, "Part 3.4"); CHECK_COND(static_cast(std::abs(test4[6] - test4[5])) >= ps, "Part 3.5"); CHECK_COND(static_cast(std::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(cur) == reinterpret_cast(last1) + 1, "Part 4.1"); last1 = cur; cur = alloc4.Alloc(1); CHECK_COND(reinterpret_cast(cur) == reinterpret_cast(last4) + 4, "Part 4.2"); last4 = cur; cur = alloc16.Alloc(1); CHECK_COND(reinterpret_cast(cur) == reinterpret_cast(last16) + 16, "Part 4.3"); last16 = cur; } alloc16.Free(alloc16.Alloc(1)); return true; }