diff --git a/core/logic/smn_core.cpp b/core/logic/smn_core.cpp index 8e90d40310..c601281d0c 100644 --- a/core/logic/smn_core.cpp +++ b/core/logic/smn_core.cpp @@ -863,11 +863,22 @@ enum NumberType static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params) { + void* addr = nullptr; + if (g_pSM->IsUsingPluginAddress(pContext)) + { + if (!g_pSM->FromPluginAddress(pContext, params[1], &addr)) + { + return pContext->ThrowNativeError("Failed to read Address!"); + } + } + else + { #ifdef PLATFORM_X86 - void *addr = reinterpret_cast(params[1]); + addr = reinterpret_cast(params[1]); #else - void *addr = pseudoAddr.FromPseudoAddress(params[1]); + addr = pseudoAddr.FromPseudoAddress(params[1]); #endif + } if (addr == NULL) { @@ -895,11 +906,22 @@ static cell_t LoadFromAddress(IPluginContext *pContext, const cell_t *params) static cell_t StoreToAddress(IPluginContext *pContext, const cell_t *params) { + void* addr = nullptr; + if (g_pSM->IsUsingPluginAddress(pContext)) + { + if (!g_pSM->FromPluginAddress(pContext, params[1], &addr)) + { + return pContext->ThrowNativeError("Failed to read Address!"); + } + } + else + { #ifdef PLATFORM_X86 - void *addr = reinterpret_cast(params[1]); + addr = reinterpret_cast(params[1]); #else - void *addr = pseudoAddr.FromPseudoAddress(params[1]); + addr = pseudoAddr.FromPseudoAddress(params[1]); #endif + } if (addr == NULL) { diff --git a/core/logic/smn_gameconfigs.cpp b/core/logic/smn_gameconfigs.cpp index eaff876a6f..0d152ed3ef 100644 --- a/core/logic/smn_gameconfigs.cpp +++ b/core/logic/smn_gameconfigs.cpp @@ -29,6 +29,7 @@ * Version: $Id$ */ +#include #include "common_logic.h" #include #include "GameConfigs.h" @@ -134,7 +135,13 @@ static cell_t smn_GameConfGetKeyValue(IPluginContext *pCtx, const cell_t *params static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params) { - Handle_t hndl = static_cast(params[1]); + int startparam = 1; + if (g_pSM->IsUsingPluginAddress(pCtx)) + { + startparam++; + } + + Handle_t hndl = static_cast(params[startparam]); HandleError herr; HandleSecurity sec; IGameConfig *gc; @@ -150,21 +157,39 @@ static cell_t smn_GameConfGetAddress(IPluginContext *pCtx, const cell_t *params) char *key; void* val; - pCtx->LocalToString(params[2], &key); + pCtx->LocalToString(params[startparam], &key); if (!gc->GetAddress(key, &val)) return 0; + // BCompat Address + if (startparam == 1) + { #ifdef PLATFORM_X86 - return (cell_t)val; + return (cell_t)val; #else - return pseudoAddr.ToPseudoAddress(val); + return pseudoAddr.ToPseudoAddress(val); #endif + } + else + { + if (!g_pSM->ToPluginAddress(pCtx, params[1], val)) + { + return pCtx->ThrowNativeError("Failed to return Address!"); + } + return 0; + } } static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params) { - Handle_t hndl = static_cast(params[1]); + int startparam = 1; + if (g_pSM->IsUsingPluginAddress(pCtx)) + { + startparam++; + } + + Handle_t hndl = static_cast(params[startparam]); HandleError herr; HandleSecurity sec; IGameConfig *gc; @@ -180,18 +205,30 @@ static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params) char *key; void *val; - pCtx->LocalToString(params[2], &key); + pCtx->LocalToString(params[startparam + 1], &key); if (!gc->GetMemSig(key, &val)) { return 0; } + // BCompat Address + if (startparam == 1) + { #ifdef PLATFORM_X86 - return (cell_t)val; + return (cell_t)val; #else - return pseudoAddr.ToPseudoAddress(val); + return pseudoAddr.ToPseudoAddress(val); #endif + } + else + { + if (!g_pSM->ToPluginAddress(pCtx, params[1], val)) + { + return pCtx->ThrowNativeError("Failed to return Address!"); + } + return 0; + } } static GameConfigsNatives s_GameConfigsNatives; diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 929b4a4a8f..0cfd0e4f11 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -724,11 +724,22 @@ static cell_t GetEntDataEnt2(IPluginContext *pContext, const cell_t *params) static cell_t LoadEntityFromHandleAddress(IPluginContext *pContext, const cell_t *params) { + void* addr = nullptr; + if (g_SourceMod.IsUsingPluginAddress(pContext)) + { + if (!g_SourceMod.FromPluginAddress(pContext, params[1], &addr)) + { + return pContext->ThrowNativeError("Failed to read Address!"); + } + } + else + { #ifdef PLATFORM_X86 - void *addr = reinterpret_cast(params[1]); + addr = reinterpret_cast(params[1]); #else - void *addr = g_SourceMod.FromPseudoAddress(params[1]); + addr = pseudoAddr.FromPseudoAddress(params[1]); #endif + } if (addr == NULL) { @@ -835,11 +846,22 @@ static cell_t SetEntDataEnt2(IPluginContext *pContext, const cell_t *params) static cell_t StoreEntityToHandleAddress(IPluginContext *pContext, const cell_t *params) { + void* addr = nullptr; + if (g_SourceMod.IsUsingPluginAddress(pContext)) + { + if (!g_SourceMod.FromPluginAddress(pContext, params[1], &addr)) + { + return pContext->ThrowNativeError("Failed to read Address!"); + } + } + else + { #ifdef PLATFORM_X86 - void *addr = reinterpret_cast(params[1]); + addr = reinterpret_cast(params[1]); #else - void *addr = g_SourceMod.FromPseudoAddress(params[1]); + addr = pseudoAddr.FromPseudoAddress(params[1]); #endif + } if (addr == NULL) { diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index e27dfbf394..182a19c1fd 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -836,6 +836,124 @@ uint32_t SourceModBase::ToPseudoAddress(void *addr) return logicore.ToPseudoAddress(addr); } +bool SourceModBase::IsUsingPluginAddress(IPluginContext* context) +{ + return context->GetRuntime()->FindPubvarByName("Address_Null", nullptr) == SP_ERROR_NONE; +} + +#pragma pack(push, 1) +struct SMAddress { + cell_t bits[8]; + + inline void* get_ptr() const { + std::int64_t ptr = 0x0; + + if (sizeof(void*) >= 8) { + ptr |= (((std::int64_t)bits[1]) << 32); + } + ptr |= ((std::int32_t)bits[0]); + + return reinterpret_cast(ptr); + } + + inline void set_ptr(void* ptr) { + if (ptr == nullptr) { + for (int i = 0; i < sizeof(bits) / sizeof(cell_t); i++) { + bits[i] = 0x0; + } + } + + std::int64_t store = 0x0; + store = reinterpret_cast(ptr); + + if (sizeof(void*) >= 8) { + bits[1] = static_cast(store >> 32); + } + bits[0] = static_cast(store); + } +}; +#pragma pack(pop) + +bool SourceModBase::ToPluginAddress(IPluginContext* context, cell_t reference, void* addr) +{ + // Enum struct Address active ? + uint32_t index; + auto runtime = context->GetRuntime(); + if (runtime->FindPubvarByName("Address_Null", &index) == SP_ERROR_NONE) { + return false; + } + + // Shouldn't happen + cell_t null_addr_addr; + if (runtime->GetPubvarAddrs(index, &null_addr_addr, nullptr) == SP_ERROR_NONE) { + return false; + } + + // Local address match, it's null address + // Do nothing... + if (null_addr_addr == reference) { + return true; + } + + SMAddress to; + context->LocalToPhysAddr(reference, reinterpret_cast(&to)); + to.set_ptr(addr); + return true; +} + +bool SourceModBase::FromPluginAddress(IPluginContext* context, cell_t reference, void** addr) +{ + // Enum struct Address active ? + uint32_t index; + auto runtime = context->GetRuntime(); + if (runtime->FindPubvarByName("Address_Null", &index) == SP_ERROR_NONE) { + return false; + } + + // Shouldn't happen + cell_t null_addr_addr; + if (runtime->GetPubvarAddrs(index, &null_addr_addr, nullptr) == SP_ERROR_NONE) { + return false; + } + + // Local address match, it's null address + if (null_addr_addr == reference) { + *addr = nullptr; + return true; + } + + SMAddress from; + context->LocalToPhysAddr(reference, reinterpret_cast(&from)); + *addr = from.get_ptr(); + return true; +} + +bool SourceModBase::PushPluginAddress(IPluginFunction* function, void* addr, int flags) +{ + // Enum struct Address active ? + uint32_t index; + auto runtime = function->GetParentRuntime(); + if (runtime->FindPubvarByName("Address_Null", &index) != SP_ERROR_NONE) { + return false; + } + + // Shouldn't happen + cell_t null_addr_addr; + if (runtime->GetPubvarAddrs(index, &null_addr_addr, nullptr) != SP_ERROR_NONE) { + return false; + } + + if (addr == nullptr) { + function->PushCell(null_addr_addr); + } else { + SMAddress sp_addr; + sp_addr.set_ptr(addr); + + function->PushArray(sp_addr.bits, sizeof(sp_addr.bits) / sizeof(cell_t)); + } + return true; +} + class ConVarRegistrar : public IConCommandBaseAccessor, public SMGlobalClass diff --git a/core/sourcemod.h b/core/sourcemod.h index 0b4eb23e9a..819bf5ca18 100644 --- a/core/sourcemod.h +++ b/core/sourcemod.h @@ -137,6 +137,10 @@ class SourceModBase : bool IsMapRunning(); void *FromPseudoAddress(uint32_t pseudoAddr); uint32_t ToPseudoAddress(void *addr); + virtual bool IsUsingPluginAddress(IPluginContext* context) override; + virtual bool ToPluginAddress(IPluginContext* context, cell_t reference, void* addr) override; + virtual bool FromPluginAddress(IPluginContext* context, cell_t reference, void** addr) override; + virtual bool PushPluginAddress(IPluginFunction* function, void* addr, int flags = 0) override; private: void ShutdownServices(); private: diff --git a/extensions/dhooks/dynhooks_sourcepawn.cpp b/extensions/dhooks/dynhooks_sourcepawn.cpp index 927f3d66c8..a1ac707ff7 100644 --- a/extensions/dhooks/dynhooks_sourcepawn.cpp +++ b/extensions/dhooks/dynhooks_sourcepawn.cpp @@ -376,8 +376,7 @@ ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour) { // The this pointer is implicitly always the first argument. void *thisPtr = pDetour->GetArgument(0); - cell_t thisAddr = GetThisPtr(thisPtr, pWrapper->thisType); - pCallback->PushCell(thisAddr); + PushThisPtr(pCallback, thisPtr, pWrapper->thisType); } // Create the structure for plugins to change/get the return value if the function returns something. diff --git a/extensions/dhooks/natives.cpp b/extensions/dhooks/natives.cpp index f228fcf306..84d617c338 100644 --- a/extensions/dhooks/natives.cpp +++ b/extensions/dhooks/natives.cpp @@ -122,7 +122,21 @@ cell_t Native_CreateHook(IPluginContext *pContext, const cell_t *params) //native Handle:DHookCreateDetour(Address:funcaddr, CallingConvention:callConv, ReturnType:returntype, ThisPointerType:thistype); cell_t Native_CreateDetour(IPluginContext *pContext, const cell_t *params) { - HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], (void *)params[1]); + void *iface = nullptr; + if (g_pSM->IsUsingPluginAddress(pContext)) + { + if (!g_pSM->FromPluginAddress(pContext, params[1], &iface)) + { + return pContext->ThrowNativeError("Failed to retrieve Address!"); + } + } + else + { + iface = (void *)(params[1]); + } + + + HookSetup *setup = new HookSetup((ReturnType)params[3], PASSFLAG_BYVAL, (CallingConvention)params[2], (ThisPointerType)params[4], iface); Handle_t hndl = handlesys->CreateHandle(g_HookSetupHandle, setup, pContext->GetIdentity(), myself->GetIdentity(), NULL); @@ -589,7 +603,18 @@ cell_t HookRawImpl(IPluginContext *pContext, const cell_t *params, int callbackI if (removalcbIndex > 0) removalcb = pContext->GetFunctionById(params[removalcbIndex]); - void *iface = (void *)(params[3]); + void *iface = nullptr; + if (g_pSM->IsUsingPluginAddress(pContext)) + { + if (!g_pSM->FromPluginAddress(pContext, params[3], &iface)) + { + return pContext->ThrowNativeError("Failed to retrieve Address!"); + } + } + else + { + iface = (void *)(params[3]); + } for(int i = g_pHooks.size() -1; i >= 0; i--) { @@ -1489,19 +1514,25 @@ cell_t Native_IsNullParam(IPluginContext *pContext, const cell_t *params) //native Address:DHookGetParamAddress(Handle:hParams, num); cell_t Native_GetParamAddress(IPluginContext *pContext, const cell_t *params) { + int startparam = 1; + if (g_pSM->IsUsingPluginAddress(pContext)) + { + startparam++; + } + HookParamsStruct *paramStruct; - if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[1])) + if(!GetCallbackArgHandleIfValidOrError(g_HookParamsHandle, g_HookReturnHandle, (void **)¶mStruct, pContext, params[startparam])) { return 0; } - if(params[2] <= 0 || params[2] > (int)paramStruct->dg->params.size()) + if(params[startparam + 1] <= 0 || params[startparam + 1] > (int)paramStruct->dg->params.size()) { - return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[2], paramStruct->dg->params.size()); + return pContext->ThrowNativeError("Invalid param number %i max params is %i", params[startparam + 1], paramStruct->dg->params.size()); } - int index = params[2] - 1; + int index = params[startparam + 1] - 1; HookParamType type = paramStruct->dg->params.at(index).type; if(type != HookParamType_StringPtr && type != HookParamType_CharPtr && type != HookParamType_VectorPtr && type != HookParamType_CBaseEntity && type != HookParamType_ObjectPtr && type != HookParamType_Edict && type != HookParamType_Unknown) @@ -1510,7 +1541,19 @@ cell_t Native_GetParamAddress(IPluginContext *pContext, const cell_t *params) } size_t offset = GetParamOffset(paramStruct, index); - return *(cell_t *)((intptr_t)paramStruct->orgParams + offset); + // BCompat Address + if (startparam == 1) + { + return *(cell_t *)((intptr_t)paramStruct->orgParams + offset); + } + else + { + if (!g_pSM->ToPluginAddress(pContext, params[1], *(void **)((intptr_t)paramStruct->orgParams + offset))) + { + return pContext->ThrowNativeError("Failed to return Address!"); + } + return 0; + } } sp_nativeinfo_t g_Natives[] = diff --git a/extensions/dhooks/vhook.cpp b/extensions/dhooks/vhook.cpp index d20eaf447d..10c36409a7 100644 --- a/extensions/dhooks/vhook.cpp +++ b/extensions/dhooks/vhook.cpp @@ -465,19 +465,31 @@ HookReturnStruct *GetReturnStruct(DHooksCallback *dg) return res; } -cell_t GetThisPtr(void *iface, ThisPointerType type) +void PushThisPtr(IPluginFunction* func, void *iface, ThisPointerType type) { if(type == ThisPointer_CBaseEntity) { - if (!iface) - return -1; - return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface); + if (!iface) { + func->PushCell(-1); + } else { + func->PushCell(gamehelpers->EntityToBCompatRef((CBaseEntity *)iface)); + } } + + if (g_pSM->IsUsingPluginAddress(func->GetParentContext())) + { + if (!g_pSM->PushPluginAddress(func, iface)) { + func->PushCell(0); + } + } + else + { #ifdef PLATFORM_X64 - return g_pSM->ToPseudoAddress(iface); + func->PushCell(g_pSM->ToPseudoAddress(iface)); #else - return (cell_t)iface; + func->PushCell((cell_t)iface); #endif + } } #if defined( WIN32 ) && !defined( PLATFORM_X64 ) @@ -500,7 +512,7 @@ void *Callback(DHooksCallback *dg, void **argStack) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { - dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType)); + PushThisPtr(dg->plugin_callback, g_SHPtr->GetIfacePtr(), dg->thisType); } if(dg->returnType != ReturnType_Void) { @@ -684,7 +696,7 @@ float Callback_float(DHooksCallback *dg, void **argStack) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { - dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType)); + PushThisPtr(dg->plugin_callback, g_SHPtr->GetIfacePtr(), dg->thisType); } returnStruct = GetReturnStruct(dg); @@ -841,7 +853,7 @@ SDKVector *Callback_vector(DHooksCallback *dg, void **argStack) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { - dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType)); + PushThisPtr(dg->plugin_callback, g_SHPtr->GetIfacePtr(), dg->thisType); } returnStruct = GetReturnStruct(dg); @@ -995,7 +1007,7 @@ string_t *Callback_stringt(DHooksCallback *dg, void **argStack) if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { - dg->plugin_callback->PushCell(GetThisPtr(g_SHPtr->GetIfacePtr(), dg->thisType)); + PushThisPtr(dg->plugin_callback, g_SHPtr->GetIfacePtr(), dg->thisType); } returnStruct = GetReturnStruct(dg); diff --git a/extensions/dhooks/vhook.h b/extensions/dhooks/vhook.h index b58f9c4ff1..b8a0290c04 100644 --- a/extensions/dhooks/vhook.h +++ b/extensions/dhooks/vhook.h @@ -338,7 +338,7 @@ class DHooksManager }; size_t GetStackArgsSize(DHooksCallback *dg); -cell_t GetThisPtr(void *iface, ThisPointerType type); +void PushThisPtr(IPluginFunction* func, void *iface, ThisPointerType type); extern IBinTools *g_pBinTools; extern HandleType_t g_HookParamsHandle; diff --git a/extensions/sdktools/vcaller.cpp b/extensions/sdktools/vcaller.cpp index 3cabcc40ae..5f9d270361 100644 --- a/extensions/sdktools/vcaller.cpp +++ b/extensions/sdktools/vcaller.cpp @@ -172,12 +172,21 @@ static cell_t PrepSDKCall_SetSignature(IPluginContext *pContext, const cell_t *p static cell_t PrepSDKCall_SetAddress(IPluginContext *pContext, const cell_t *params) { + if (g_pSM->IsUsingPluginAddress(pContext)) + { + if (!g_pSM->FromPluginAddress(pContext, params[1], &s_call_addr)) + { + return pContext->ThrowNativeError("Couldn't read addr!"); + } + } + else + { #ifdef PLATFORM_X86 - s_call_addr = reinterpret_cast(params[1]); + s_call_addr = reinterpret_cast(params[1]); #else - s_call_addr = g_pSM->FromPseudoAddress(params[1]); + s_call_addr = g_pSM->FromPseudoAddress(params[1]); #endif - + } return (s_call_addr != NULL) ? 1 : 0; } @@ -413,6 +422,39 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) startparam++; } break; + case ValveCall_SMAddress: + { + //params[startparam] is an address to a pointer to THIS + //params following this are params to the method we will invoke later + if (startparam > numparams) + { + vc->stk_put(ptr); + return pContext->ThrowNativeError("Expected a ThisPtr address, it wasn't found"); + } + + //note: varargs pawn args are passed by-ref + void *thisptr = nullptr; + if (!g_pSM->ToPluginAddress(pContext, params[startparam], &thisptr)) + { + vc->stk_put(ptr); + return pContext->ThrowNativeError("Failed to read ThisPtr address!"); + } + + if (thisptr == nullptr) + { + vc->stk_put(ptr); + return pContext->ThrowNativeError("ThisPtr address cannot be null"); + } + else if (reinterpret_cast(thisptr) < VALID_MINIMUM_MEMORY_ADDRESS) + { + vc->stk_put(ptr); + return pContext->ThrowNativeError("Invalid ThisPtr address 0x%x is pointing to reserved memory.", thisptr); + } + + *(void **)ptr = thisptr; + startparam++; + } + break; default: { vc->stk_put(ptr); @@ -429,7 +471,8 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) { startparam += 2; } else if (vc->retinfo->vtype == Valve_Vector - || vc->retinfo->vtype == Valve_QAngle) + || vc->retinfo->vtype == Valve_QAngle + || vc->retinfo->vtype == Valve_SMAddress) { startparam += 1; } @@ -506,11 +549,12 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) pContext->StringToLocalUTF8(params[retparam], *addr, *(char **)vc->retbuf, &written); return (cell_t)written; } else if (vc->retinfo->vtype == Valve_Vector - || vc->retinfo->vtype == Valve_QAngle) + || vc->retinfo->vtype == Valve_QAngle + || vc->retinfo->vtype == Valve_SMAddress) { if (numparams < 2) { - return pContext->ThrowNativeError("Expected argument (2) for Float[3] storage"); + return pContext->ThrowNativeError("Expected argument (2) for return storage"); } if (EncodeValveParam(pContext, params[retparam], vc, vc->retinfo, vc->retbuf) == Data_Fail) diff --git a/extensions/sdktools/vdecoder.cpp b/extensions/sdktools/vdecoder.cpp index 881fa667a9..a10a0a5282 100644 --- a/extensions/sdktools/vdecoder.cpp +++ b/extensions/sdktools/vdecoder.cpp @@ -164,6 +164,23 @@ size_t ValveParamToBinParam(ValveType type, return sizeof(float); } } + break; + case Valve_SMAddress: + { + info->flags = flags; + if (flags & PASSFLAG_ASPOINTER) + { + needs_extra = true; + info->type = PassType_Basic; + info->size = sizeof(void**); + return sizeof(void**) + sizeof(void*); + } else { + info->type = PassType_Basic; + info->size = sizeof(void*); + return sizeof(void*); + } + } + break; } return 0; @@ -278,6 +295,21 @@ DataStatus EncodeValveParam(IPluginContext *pContext, return Data_Okay; } + case Valve_SMAddress: + { + if (data->flags & PASSFLAG_ASPOINTER) + { + buffer = *(void ***)buffer; + } + + if (!g_pSM->ToPluginAddress(pContext, param, *(void **)buffer)) + { + pContext->ThrowNativeError("Failed to store address!"); + return Data_Fail; + } + return Data_Okay; + } + break; } return Data_Fail; @@ -579,6 +611,34 @@ DataStatus DecodeValveParam(IPluginContext *pContext, *(char **)buffer = addr; return Data_Okay; } + break; + case Valve_SMAddress: + { + if (data->flags & PASSFLAG_ASPOINTER) + { + *(void ***)buffer = (void **)((unsigned char *)_buffer + pCall->stackEnd + data->obj_offset); + buffer = *(void ***)buffer; + } + void* thisPtr = nullptr; + if (!g_pSM->FromPluginAddress(pContext, param, &thisPtr)) + { + pContext->ThrowNativeError("Failed to read address!"); + return Data_Fail; + } + if (thisPtr == nullptr) + { + if (data->decflags & VDECODE_FLAG_ALLOWNULL) + { + *(void **)buffer = nullptr; + return Data_Okay; + } + pContext->ThrowNativeError("Null Address isn't allowed!"); + return Data_Fail; + } + *(void **)buffer = thisPtr; + return Data_Okay; + } + break; } return Data_Fail; diff --git a/extensions/sdktools/vdecoder.h b/extensions/sdktools/vdecoder.h index 16478cf101..64e50dc06a 100644 --- a/extensions/sdktools/vdecoder.h +++ b/extensions/sdktools/vdecoder.h @@ -53,6 +53,7 @@ enum ValveType Valve_Edict, /**< Edict */ Valve_String, /**< String */ Valve_Bool, /**< Boolean */ + Valve_SMAddress, /**< SourceMod-Address */ Valve_Object, /**< Object, not matching one of the above types */ }; @@ -76,14 +77,15 @@ enum DataStatus */ enum ValveCallType { - ValveCall_Static, /**< Static call */ - ValveCall_Entity, /**< Thiscall (CBaseEntity implicit first parameter) */ - ValveCall_Player, /**< Thiscall (CBasePlayer implicit first parameter) */ - ValveCall_GameRules, /**< Thiscall (CGameRules implicit first paramater) */ - ValveCall_EntityList, /**< Thiscall (CGlobalEntityList implicit first paramater) */ - ValveCall_Raw, /**< Thiscall (address explicit first parameter) */ + ValveCall_Static, /**< Static call */ + ValveCall_Entity, /**< Thiscall (CBaseEntity implicit first parameter) */ + ValveCall_Player, /**< Thiscall (CBasePlayer implicit first parameter) */ + ValveCall_GameRules, /**< Thiscall (CGameRules implicit first paramater) */ + ValveCall_EntityList, /**< Thiscall (CGlobalEntityList implicit first paramater) */ + ValveCall_Raw, /**< Thiscall (address explicit first parameter) */ ValveCall_Server, /**< Thiscall (CBaseServer implicit first parameter) */ ValveCall_Engine, /**< Thiscall (CVEngineServer implicit first parameter) */ + ValveCall_SMAddress /**< Thiscall (SourceMod-Address explicit first parameter) */ }; /** diff --git a/plugins/include/sdktools.inc b/plugins/include/sdktools.inc index 07fc55f82f..1dc0c94e1f 100644 --- a/plugins/include/sdktools.inc +++ b/plugins/include/sdktools.inc @@ -62,7 +62,8 @@ enum SDKCallType SDKCall_EntityList, /**< CGlobalEntityList call */ SDKCall_Raw, /**< |this| pointer with an arbitrary address */ SDKCall_Server, /**< CBaseServer call */ - SDKCall_Engine /**< CVEngineServer call */ + SDKCall_Engine, /**< CVEngineServer call */ + SDKCall_SMAddress /**< |this| pointer retrieved from a SourceMod Address */ }; enum SDKLibrary @@ -88,7 +89,8 @@ enum SDKType SDKType_Float, /**< Float (any) */ SDKType_Edict, /**< edict_t (always as pointer) */ SDKType_String, /**< NULL-terminated string (always as pointer) */ - SDKType_Bool /**< Boolean (any) */ + SDKType_Bool, /**< Boolean (any) */ + SDKType_SMAddress /**< The value is retrieved from a SourceMod Address, the size is sizeof(void*) */ }; enum SDKPassMethod diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 1927015680..3c7a0f378f 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -725,10 +725,169 @@ enum NumberType NumberType_Int32 }; -enum Address +/** + * Represents a memory address. I.e sizeof(void*) + */ +enum struct Address { - Address_Null = 0 // a typical invalid result when an address lookup fails -}; + /** + * Do no manipulate the bits array directly. + * SourceMod makes no guarantee in which way the array is filled. + * Always go through the provided methods to update the Address value. + */ + int bits[8]; + + /** + * Offsets the address by the amount of bytes. + * + * @param offset Amount of bytes. + */ + /*void Offset(int offset) { + if ((offset & 0x80000000) != 0x0) { + this.Sub(~offset + 0x1); + } else { + this.Add(offset); + } + }*/ + + /** + * Adds the given amount of bytes to the address. + * + * @param offset Amount of bytes. + */ + /*void Add(int offset) { + // Subtract if number is negative + if ((offset & 0x80000000) != 0x0) { + this.Sub(~offset + 0x1); + } else { + this.__Add(offset, 0); + } + }*/ + + /** + * Subtracts the address by the given amount of bytes. + * + * @param offset Amount of bytes. + */ + /*void Sub(int offset) { + // Addition if number is negative + if ((offset & 0x80000000) != 0x0) { + this.Add(~offset + 0x1); + } else { + this.__Sub(offset, 0); + } + }*/ + + /** + * Checks whether or not the address would be a nullptr in C++. + * + * @return True if nullptr, false otherwise. + */ + bool IsNull() { + return ( + this.bits[0] == 0x0 + && this.bits[1] == 0x0 + && this.bits[2] == 0x0 + && this.bits[3] == 0x0 + && this.bits[4] == 0x0 + && this.bits[5] == 0x0 + && this.bits[6] == 0x0 + && this.bits[7] == 0x0) + } + + /** + * Mutiplies the address by the given value in bytes. + */ + void Mul(int value) { + AddressRefMultInt(this, value); + } + + /** + * Divides the address by the given value in bytes. + * @error Value is 0 or negative. + */ + void Div(int value) { + AddressRefDivInt(this, value); + } + + /** + * Increases the address value by the given amount of bytes. + */ + void Add(int value) { + AddressRefDivInt(this, value); + } + + /** + * Decreases the address value by the given amount of bytes. + */ + void Sub(int value) { + AddressRefSubInt(this, value); + } + + /** + * Performs a modulo on the address with the given value in bytes. + * @error Value is negative. + */ + void Mod(int value) { + AddressRefModInt(this, value); + } +} +public const Address Address_Null; + +native Address IntAddressMult(int a, Address b); +//stock Address operator*(int oper1, Address oper2) { return IntAddressMult(oper1, oper2); } + +native void AddressRefMultInt(Address a, int b); +native void AddressRefDivInt(Address a, int b); +native void AddressRefAddInt(Address a, int b); +native void AddressRefSubInt(Address a, int b); +native void AddressRefModInt(Address a, int b); + +native Address AddressMultInt(Address a, int b); +native Address AddressDivInt(Address a, int b); +native Address AddressAddInt(Address a, int b); +native Address AddressSubInt(Address a, int b); +native Address AddressModInt(Address a, int b); + +//stock Address operator*(Address oper1, int oper2) { return AddressMultInt(oper1, oper2); } +//stock Address operator/(Address oper1, int oper2) { return AddressDivInt(oper1, oper2); } +//stock Address operator+(Address oper1, int oper2) { return AddressAddInt(oper1, oper2); } +//stock Address operator-(Address oper1, int oper2) { return AddressSubInt(oper1, oper2); } +//stock Address operator%(Address oper1, int oper2) { return AddressModInt(oper1, oper2); } + +native Address AddressMul(Address a, Address b); +native Address AddressDiv(Address a, Address b); +native Address AddressAdd(Address a, Address b); +native Address AddressSub(Address a, Address b); +native Address AddressMod(Address a, Address b); + +//stock Address operator*(Address oper1, Address oper2) { return AddressMul(oper1, oper2); } +//stock Address operator/(Address oper1, Address oper2) { return AddressDiv(oper1, oper2); } +//stock Address operator+(Address oper1, Address oper2) { return AddressAdd(oper1, oper2); } +//stock Address operator-(Address oper1, Address oper2) { return AddressSub(oper1, oper2); } +//stock Address operator%(Address oper1, Address oper2) { return AddressMod(oper1, oper2); } + +native bool AddressGreaterThan(Address a, Address b); +native bool AddressGreaterEqual(Address a, Address b); +native bool AddressLowerThan(Address a, Address b); +native bool AddressLowerEqual(Address a, Address b); +native bool AddressEqual(Address a, Address b); +native bool AddressNotEqual(Address a, Address b); +native bool AddressNot(Address a); + +//stock bool operator>(Address oper1, Address oper2) { return AddressGreaterThan(oper1, oper2); } +//stock bool operator>=(Address oper1, Address oper2) { return AddressGreaterEqual(oper1, oper2); } +//stock bool operator<(Address oper1, Address oper2) { return AddressLowerThan(oper1, oper2); } +//stock bool operator<=(Address oper1, Address oper2) { return AddressLowerEqual(oper1, oper2); } +//stock bool operator==(Address oper1, Address oper2) { return AddressEqual(oper1, oper2); } +//stock bool operator!=(Address oper1, Address oper2) { return AddressNotEqual(oper1, oper2); } +//stock bool operator!(Address oper1) { return AddressNot(oper1); } + +native Address AddressInc(Address a); +native Address AddressDec(Address a, Address b); + +//stock Address operator++(Address oper) { return AddressInc(oper); } +//stock Address operator--(Address oper) { return AddressDec(oper); } /** * Load up to 4 bytes from a memory address. @@ -754,6 +913,28 @@ native any LoadFromAddress(Address addr, NumberType size); */ native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true); +/** + * Loads an Address value from a memory address. + * The amount of bytes read will be the sizeof(void*) in C++ + * + * @param addr Address to a memory location. + * @return The new address value that is stored at that address. + * @error Address location is null or pointing to reserved memory. + */ +native Address LoadAddressFromAddress(Address addr); + +/** + * Store an Address value to a memory address. + * The amount of bytes written will be the sizeof(void*) in C++ + * + * @param addr Address to a memory location. + * @param data Value to store at the address. + * @param updateMemAccess If true, SourceMod will set read / write / exec permissions + * on the memory page being written to. + * @error Address is null or pointing to reserved memory. + */ +native void StoreAddressToAddress(Address addr, Address data, bool updateMemAccess = true); + methodmap FrameIterator < Handle { // Creates a stack frame iterator to build your own stack traces. // @return New handle to a FrameIterator. diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 78c327bc3d..20e7f53602 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -42,7 +42,7 @@ #include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" -#define SMINTERFACE_SOURCEMOD_VERSION 14 +#define SMINTERFACE_SOURCEMOD_VERSION 15 /** * @brief Forward declaration of the KeyValues class. @@ -319,18 +319,44 @@ namespace SourceMod virtual bool IsMapRunning() = 0; /** - * @brief Converts 32-bit pseudo address to memory address on 64-bit platforms. - * - * @return Memory address, or nullptr if pseudo address could not be converted. + * @brief Deprecated please use FromPluginAddress instead. */ virtual void *FromPseudoAddress(uint32_t pseudoAddr) = 0; /** - * @brief Converts memory address to 32-bit pseudo address on 64-bit platforms. - * - * @return Pseudo address, or 0 if memory address could not be converted. + * @brief Deprecated please use ToPluginAddress instead. */ virtual uint32_t ToPseudoAddress(void *addr) = 0; + + /** + * @brief Whether or not a given plugin uses. + */ + virtual bool IsUsingPluginAddress(SourcePawn::IPluginContext* context) = 0; + + /** + * @brief Stores a memory address into SM plugin Address. + * + * @param context The plugin context the reference is from. + * @param reference SP reference to an Address variable. + * @param addr The memory address to convert. + * @return True if successful, False otherwise. + */ + virtual bool ToPluginAddress(SourcePawn::IPluginContext* context, cell_t reference, void* addr) = 0; + + /** + * @brief Converts SM Plugin Address into a memory address. + * + * @param context The plugin context the reference is from. + * @param reference SP reference to an Address variable. + * @param addr Variable to store the memory address into. + * @return True if successful, False otherwise. + */ + virtual bool FromPluginAddress(SourcePawn::IPluginContext* context, cell_t reference, void** addr) = 0; + + /** + * @brief Pushes a memory address as a SM Plugin Address. + */ + virtual bool PushPluginAddress(SourcePawn::IPluginFunction* function, void* addr, int flags = 0) = 0; }; } diff --git a/public/amtl b/public/amtl index 285b4f853c..2d3b1a3378 160000 --- a/public/amtl +++ b/public/amtl @@ -1 +1 @@ -Subproject commit 285b4f853c0003023838140113e3ec066bd800c6 +Subproject commit 2d3b1a3378a3728637f26660c9ffc2df3189cf62 diff --git a/sourcepawn b/sourcepawn index c96fab0258..6e00170bb0 160000 --- a/sourcepawn +++ b/sourcepawn @@ -1 +1 @@ -Subproject commit c96fab0258aacc360866856e0c9e8de418ade083 +Subproject commit 6e00170bb00c06fcd14737ceabc9341d4a0410c7