From 8b26f29d547485c55331ac064405e9e289535c1a Mon Sep 17 00:00:00 2001 From: s1lent Date: Mon, 29 Jul 2019 03:43:06 +0700 Subject: [PATCH] Fix SetHookChainArg crash due to incorrect pointer to argument (hookctx_t gets the original function as the base address of the arguments, some compilers do UB and so for this reason hookctx_t has been reworked and now uses tuple). Update reapi.inc - added ATYPE_BOOL and ATYPE_EVARS types Compiler: added option flag -static-libstdc++ --- reapi/build.gradle | 5 +- .../extra/amxmodx/scripting/include/reapi.inc | 4 +- reapi/src/hook_callback.h | 119 +++++++++--------- reapi/src/natives/natives_hookchains.cpp | 8 +- shared_gcc.gradle | 6 +- shared_icc.gradle | 6 +- version_script.lds | 8 ++ 7 files changed, 80 insertions(+), 76 deletions(-) create mode 100644 version_script.lds diff --git a/reapi/build.gradle b/reapi/build.gradle index 6b29610..4833ccd 100644 --- a/reapi/build.gradle +++ b/reapi/build.gradle @@ -57,7 +57,7 @@ void setupToolchain(NativeBinarySpec b) { pchSourceSet: 'reapi_pch' ) } - cfg.compilerOptions.languageStandard = 'c++11' + cfg.compilerOptions.languageStandard = 'c++14' cfg.defines([ '_stricmp': 'strcasecmp', '_strnicmp': 'strncasecmp', @@ -71,6 +71,9 @@ void setupToolchain(NativeBinarySpec b) { cfg.compilerOptions.args '-Qoption,cpp,--treat_func_as_string_literal_cpp', '-inline-forceinline', '-no-ansi-alias' } + cfg.linkerOptions.args '-Wl,--version-script=../version_script.lds', '-Wl,--gc-sections' + cfg.compilerOptions.args '-ffunction-sections', '-fdata-sections' // Remove unused code and data + cfg.compilerOptions.args '-Wall', '-Wno-unknown-pragmas', '-msse2', '-fomit-frame-pointer', '-fvisibility=default', '-fvisibility-inlines-hidden', '-fno-rtti', '-g0', '-s', '-fno-exceptions' } diff --git a/reapi/extra/amxmodx/scripting/include/reapi.inc b/reapi/extra/amxmodx/scripting/include/reapi.inc index d6d2f81..03b3014 100644 --- a/reapi/extra/amxmodx/scripting/include/reapi.inc +++ b/reapi/extra/amxmodx/scripting/include/reapi.inc @@ -116,7 +116,9 @@ enum AType ATYPE_FLOAT, ATYPE_STRING, ATYPE_CLASSPTR, - ATYPE_EDICT + ATYPE_EDICT, + ATYPE_EVARS, + ATYPE_BOOL }; enum HookChain diff --git a/reapi/src/hook_callback.h b/reapi/src/hook_callback.h index 4ba9e39..b29a4a9 100644 --- a/reapi/src/hook_callback.h +++ b/reapi/src/hook_callback.h @@ -1,5 +1,7 @@ #pragma once +#include + // hookchain return type enum HookChainState { @@ -17,7 +19,8 @@ enum AType : uint8 ATYPE_STRING, ATYPE_CLASSPTR, ATYPE_EDICT, - ATYPE_EVARS + ATYPE_EVARS, + ATYPE_BOOL }; struct retval_t @@ -44,6 +47,7 @@ inline AType getApiType(char[]) { return ATYPE_STRING; } inline AType getApiType(CBaseEntity *) { return ATYPE_CLASSPTR; } inline AType getApiType(edict_t *) { return ATYPE_EDICT; } inline AType getApiType(entvars_t *) { return ATYPE_EVARS; } +inline AType getApiType(bool) { return ATYPE_BOOL; } template inline AType getApiType(T *) { return ATYPE_INTEGER; } @@ -63,64 +67,47 @@ bool hasStringArgs(T, f_args... args) #define MAX_HOOKCHAIN_ARGS 12u -template -void setupArgTypes(AType args_type[], T1, T2, T3, T4, t_args... args) -{ - if (current + 4 <= MAX_HOOKCHAIN_ARGS) - *(uint32 *)&args_type[current] = getApiType(T1()) | (getApiType(T2()) << 8) | (getApiType(T3()) << 16) | (getApiType(T4()) << 24); - if (sizeof...(args) && current + 4 < MAX_HOOKCHAIN_ARGS) - setupArgTypes(args_type, args...); -} - -template -void setupArgTypes(AType args_type[], T1, T2, T3) -{ - if (current + 3 <= MAX_HOOKCHAIN_ARGS) - *(uint32 *)&args_type[current] = getApiType(T1()) | (getApiType(T2()) << 8) | (getApiType(T3()) << 16); - else - setupArgTypes(args_type, T1(), T2()); -} - -template -void setupArgTypes(AType args_type[], T1, T2) -{ - if (current + 2 <= MAX_HOOKCHAIN_ARGS) - *(uint16 *)&args_type[current] = getApiType(T1()) | (getApiType(T2()) << 8); - else - setupArgTypes(args_type, T1()); -} - -template -void setupArgTypes(AType args_type[], T) -{ - if (current + 1 <= MAX_HOOKCHAIN_ARGS) - args_type[current] = getApiType(T()); -} - -template -void setupArgTypes(AType args_type[]) -{ -} - struct hookctx_t { template - hookctx_t(size_t arg_count, t_args... args) + hookctx_t(size_t arg_count, t_args&&... args) { - args_count = min(arg_count, MAX_HOOKCHAIN_ARGS); - if (hasStringArgs(args...)) { tempstrings_used = 0; } - setupArgTypes(args_type, args...); + args_count = min(arg_count, MAX_HOOKCHAIN_ARGS); + setArgs(std::forward_as_tuple(args...)); } - void reset(size_t arg_ptr, AType ret_type = ATYPE_INTEGER) + template ::type>::value, + std::enable_if_t= size>* = nullptr> // if current >= size + void setArgs(tuple_t &&t) + { + } + + template ::type>::value, + std::enable_if_t* = nullptr> // if current < size + void setArgs(tuple_t &&t) + { + // current iteration + if (current < MAX_HOOKCHAIN_ARGS) + { + auto &arg = std::get(std::forward(t)); + args[current].handle = (size_t)&arg; + args[current].type = getApiType(arg); + setArgs(std::forward(t)); // call next + } + } + + void reset(AType ret_type = ATYPE_INTEGER) { retVal.set = false; retVal.type = ret_type; - args_ptr = arg_ptr; } char* get_temp_string(AMX* amx) @@ -140,29 +127,34 @@ struct hookctx_t s_temp_strings.pop(tempstrings_used); } - retval_t retVal; - size_t args_count; - size_t args_ptr; - size_t tempstrings_used; - AType args_type[MAX_HOOKCHAIN_ARGS]; + retval_t retVal = {false,ATYPE_INTEGER}; + size_t tempstrings_used = 0; + struct args_t + { + size_t handle; + AType type; + }; + + size_t args_count = 0; + args_t args[MAX_HOOKCHAIN_ARGS] = {0u, ATYPE_INTEGER}; static CTempStrings s_temp_strings; }; extern hookctx_t* g_hookCtx; template -NOINLINE void DLLEXPORT _callVoidForward(const hook_t* hook, original_t original, volatile f_args... args) +NOINLINE void DLLEXPORT _callVoidForward(const hook_t* hook, original_t original, f_args&&... args) { auto hookCtx = g_hookCtx; - hookCtx->reset(size_t(&original) + sizeof(original)); + hookCtx->reset(); int hc_state = HC_CONTINUE; for (auto fwd : hook->pre) { if (likely(fwd->GetState() == FSTATE_ENABLED)) { - auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), args...); + auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), std::forward(args)...); if (unlikely(ret == HC_BREAK)) { return; @@ -175,13 +167,13 @@ NOINLINE void DLLEXPORT _callVoidForward(const hook_t* hook, original_t original if (hc_state != HC_SUPERCEDE) { g_hookCtx = nullptr; - original(args...); + original(std::forward(args)...); g_hookCtx = hookCtx; } for (auto fwd : hook->post) { if (likely(fwd->GetState() == FSTATE_ENABLED)) { - auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), args...); + auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), std::forward(args)...); if (unlikely(ret == HC_BREAK)) break; @@ -190,7 +182,7 @@ NOINLINE void DLLEXPORT _callVoidForward(const hook_t* hook, original_t original } template -void callVoidForward(size_t func, original_t original, f_args... args) +void callVoidForward(size_t func, original_t original, f_args&&... args) { hookctx_t hookCtx(sizeof...(args), args...); hookctx_t* save = g_hookCtx; @@ -205,17 +197,18 @@ void callVoidForward(size_t func, original_t original, f_args... args) } template -NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, volatile f_args... args) +NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, f_args&&... args) { auto hookCtx = g_hookCtx; - hookCtx->reset(size_t(&original) + sizeof(original), getApiType(R())); + hookCtx->reset(getApiType(R())); + int hc_state = HC_CONTINUE; for (auto fwd : hook->pre) { if (likely(fwd->GetState() == FSTATE_ENABLED)) { - auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), args...); + auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), std::forward(args)...); if (likely(ret == HC_CONTINUE)) { continue; @@ -238,7 +231,7 @@ NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, volat if (likely(hc_state != HC_SUPERCEDE)) { g_hookCtx = nullptr; - auto retVal = original(args...); + auto retVal = original(std::forward(args)...); g_hookCtx = hookCtx; if (unlikely(!hookCtx->retVal.set)) { @@ -259,7 +252,7 @@ NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, volat for (auto fwd : hook->post) { if (likely(fwd->GetState() == FSTATE_ENABLED)) { - auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), args...); + auto ret = g_amxxapi.ExecuteForward(fwd->GetIndex(), std::forward(args)...); if (unlikely(ret == HC_BREAK)) break; @@ -270,7 +263,7 @@ NOINLINE R DLLEXPORT _callForward(const hook_t* hook, original_t original, volat } template -R callForward(size_t func, original_t original, f_args... args) +R callForward(size_t func, original_t original, f_args&&... args) { static_assert(sizeof(R) <= sizeof(int), "invalid hookchain return type size > sizeof(int)"); diff --git a/reapi/src/natives/natives_hookchains.cpp b/reapi/src/natives/natives_hookchains.cpp index c5ede56..5c8b03a 100644 --- a/reapi/src/natives/natives_hookchains.cpp +++ b/reapi/src/natives/natives_hookchains.cpp @@ -255,8 +255,7 @@ cell AMX_NATIVE_CALL SetHookChainArg(AMX *amx, cell *params) return FALSE; } - AType type = g_hookCtx->args_type[number]; - + AType type = g_hookCtx->args[number].type; if (unlikely(params[arg_type] != type)) { AMXX_LogError(amx, AMX_ERR_NATIVE, "%s: invalid argument type provided.", __FUNCTION__); @@ -264,7 +263,7 @@ cell AMX_NATIVE_CALL SetHookChainArg(AMX *amx, cell *params) } cell* srcAddr = getAmxAddr(amx, params[arg_value]); - size_t destAddr = g_hookCtx->args_ptr + number * sizeof(int); + size_t destAddr = g_hookCtx->args[number].handle; switch (type) { @@ -272,6 +271,9 @@ cell AMX_NATIVE_CALL SetHookChainArg(AMX *amx, cell *params) case ATYPE_FLOAT: *(cell *)destAddr = *srcAddr; break; + case ATYPE_BOOL: + *(bool *)destAddr = *srcAddr != 0; + break; case ATYPE_STRING: *(char **)destAddr = getAmxString(srcAddr, g_hookCtx->get_temp_string(amx), CTempStrings::STRING_LEN); break; diff --git a/shared_gcc.gradle b/shared_gcc.gradle index a56ba45..1d1e5c7 100644 --- a/shared_gcc.gradle +++ b/shared_gcc.gradle @@ -16,14 +16,13 @@ rootProject.ext.createGccConfig = { boolean release, BinaryKind binKind -> 'linux': null, '__linux__': null, 'NDEBUG': null, - '_GLIBCXX_USE_CXX11_ABI': 0, // don't use specific c++11 features from GCC 5.X for backward compatibility to earlier version ABI libstdc++.so.6 ], ), linkerOptions: new GccToolchainConfig.LinkerOptions( stripSymbolTable: false, staticLibGcc: false, - staticLibStdCpp: false, + staticLibStdCpp: true, ), librarianOptions: new GccToolchainConfig.LibrarianOptions( @@ -42,14 +41,13 @@ rootProject.ext.createGccConfig = { boolean release, BinaryKind binKind -> 'linux': null, '__linux__': null, 'NDEBUG': null, - '_GLIBCXX_USE_CXX11_ABI': 0, // don't use specific c++11 features from GCC 5.X for backward compatibility to earlier version ABI libstdc++.so.6 ], ), linkerOptions: new GccToolchainConfig.LinkerOptions( stripSymbolTable: false, staticLibGcc: false, - staticLibStdCpp: false, + staticLibStdCpp: true, ), librarianOptions: new GccToolchainConfig.LibrarianOptions( diff --git a/shared_icc.gradle b/shared_icc.gradle index f844c8a..3490e03 100644 --- a/shared_icc.gradle +++ b/shared_icc.gradle @@ -19,14 +19,13 @@ rootProject.ext.createIccConfig = { boolean release, BinaryKind binKind -> 'linux': null, '__linux__': null, 'NDEBUG': null, - '_GLIBCXX_USE_CXX11_ABI': 0, // don't use specific c++11 features from GCC 5.X for backward compatibility to earlier version ABI libstdc++.so.6 ], ), linkerOptions: new GccToolchainConfig.LinkerOptions( interProceduralOptimizations: true, // -ipo stripSymbolTable: true, - staticLibStdCpp: false, + staticLibStdCpp: true, staticLibGcc: false, staticIntel: true, ), @@ -49,14 +48,13 @@ rootProject.ext.createIccConfig = { boolean release, BinaryKind binKind -> 'linux': null, '__linux__': null, 'NDEBUG': null, - '_GLIBCXX_USE_CXX11_ABI': 0, // don't use specific c++11 features from GCC 5.X for backward compatibility to earlier version ABI libstdc++.so.6 ], ), linkerOptions: new GccToolchainConfig.LinkerOptions( interProceduralOptimizations: false, stripSymbolTable: false, - staticLibStdCpp: false, + staticLibStdCpp: true, staticLibGcc: false, staticIntel: true, ), diff --git a/version_script.lds b/version_script.lds new file mode 100644 index 0000000..a120260 --- /dev/null +++ b/version_script.lds @@ -0,0 +1,8 @@ +REAPI_ABI_1.0 { + global: + Meta_*; + GiveFnptrsToDll; + AMXX_*; + local: + *; +};