diff --git a/core/logic/MemoryPointer.cpp b/core/logic/MemoryPointer.cpp index f4c0429d46..753da0a4ba 100644 --- a/core/logic/MemoryPointer.cpp +++ b/core/logic/MemoryPointer.cpp @@ -50,6 +50,11 @@ MemoryPointer::~MemoryPointer() } } +void MemoryPointer::Delete() +{ + delete this; +} + void* MemoryPointer::Get() { return m_ptr; diff --git a/core/logic/MemoryPointer.h b/core/logic/MemoryPointer.h index 23a123d09f..4602122cd3 100644 --- a/core/logic/MemoryPointer.h +++ b/core/logic/MemoryPointer.h @@ -44,6 +44,7 @@ class MemoryPointer : public SourceMod::IMemoryPointer // SourceMod::IMemoryPointer virtual ~MemoryPointer(); + virtual void Delete() override; virtual void* Get() override; virtual cell_t GetSize() override; protected: diff --git a/core/logic/smn_core.cpp b/core/logic/smn_core.cpp index b03f8741f7..f5e6b8a645 100644 --- a/core/logic/smn_core.cpp +++ b/core/logic/smn_core.cpp @@ -110,7 +110,7 @@ class CoreNativeHelpers : { if (type == g_MemoryPtr) { - delete (IMemoryPointer *) object; + ((IMemoryPointer *)object)->Delete(); } else if (type == g_FrameIter) { @@ -1068,6 +1068,84 @@ static cell_t MemoryPointer_Load(IPluginContext *pContext, const cell_t *params) return ptr->Load(bytesSize, params[3]); } +static cell_t MemoryPointer_StoreMemoryPointer(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMemoryPointer *ptr; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + hndl = (Handle_t)params[2]; + IMemoryPointer *store; + if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&store)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + ptr->StorePtr(store->Get(), params[3], params[4] != 0); +} + +static cell_t MemoryPointer_LoadMemoryPointer(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMemoryPointer *ptr; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + auto newPtr = new MemoryPointer(ptr->LoadPtr(params[2]), 0); + + Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pContext->GetIdentity(), g_pCoreIdent, NULL); + if (newHandle == BAD_HANDLE) + { + delete newPtr; + return BAD_HANDLE; + } + + return newHandle; +} + +static cell_t MemoryPointer_Offset(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMemoryPointer *ptr; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + auto newPtr = new MemoryPointer((void*)(((intptr_t)ptr->Get()) + params[2]), 0); + Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pContext->GetIdentity(), g_pCoreIdent, NULL); + if (newHandle == BAD_HANDLE) + { + delete newPtr; + return BAD_HANDLE; + } + + return newHandle; +} + static cell_t FrameIterator_Create(IPluginContext *pContext, const cell_t *params) { IFrameIterator *it = pContext->CreateFrameIterator(); @@ -1261,6 +1339,9 @@ REGISTER_NATIVES(coreNatives) {"MemoryPointer.MemoryPointer", MemoryPointer_Create}, {"MemoryPointer.Store", MemoryPointer_Store}, {"MemoryPointer.Load", MemoryPointer_Load}, + {"MemoryPointer.StoreMemoryPointer", MemoryPointer_StoreMemoryPointer}, + {"MemoryPointer.LoadMemoryPointer", MemoryPointer_LoadMemoryPointer}, + {"MemoryPointer.Offset", MemoryPointer_Offset}, {"FrameIterator.FrameIterator", FrameIterator_Create}, {"FrameIterator.Next", FrameIterator_Next}, diff --git a/core/logic/smn_gameconfigs.cpp b/core/logic/smn_gameconfigs.cpp index eaff876a6f..f9b7768b20 100644 --- a/core/logic/smn_gameconfigs.cpp +++ b/core/logic/smn_gameconfigs.cpp @@ -31,6 +31,7 @@ #include "common_logic.h" #include +#include "MemoryPointer.h" #include "GameConfigs.h" HandleType_t g_GameConfigsType; @@ -194,6 +195,78 @@ static cell_t smn_GameConfGetMemSig(IPluginContext *pCtx, const cell_t *params) #endif } +extern HandleType_t g_MemoryPtr; + +static cell_t smn_GameConfGetAddressEx(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IGameConfig *gc; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=handlesys->ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr); + } + + char *key; + void* val; + pCtx->LocalToString(params[2], &key); + + if (!gc->GetAddress(key, &val) || val == nullptr) + return BAD_HANDLE; + + auto newPtr = new MemoryPointer(val, 0); + Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pCtx->GetIdentity(), g_pCoreIdent, NULL); + if (newHandle == BAD_HANDLE) + { + delete newPtr; + return BAD_HANDLE; + } + + return newHandle; +} + +static cell_t smn_GameConfGetMemSigEx(IPluginContext *pCtx, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IGameConfig *gc; + + sec.pOwner = NULL; + sec.pIdentity = g_pCoreIdent; + + if ((herr=handlesys->ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&gc)) + != HandleError_None) + { + return pCtx->ThrowNativeError("Invalid game config handle %x (error %d)", hndl, herr); + } + + char *key; + void *val; + pCtx->LocalToString(params[2], &key); + + if (!gc->GetMemSig(key, &val) || val == nullptr) + { + return BAD_HANDLE; + } + + auto newPtr = new MemoryPointer(val, 0); + Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pCtx->GetIdentity(), g_pCoreIdent, NULL); + if (newHandle == BAD_HANDLE) + { + delete newPtr; + return BAD_HANDLE; + } + + return newHandle; +} + static GameConfigsNatives s_GameConfigsNatives; REGISTER_NATIVES(gameconfignatives) @@ -207,6 +280,10 @@ REGISTER_NATIVES(gameconfignatives) {"GameData.GameData", smn_LoadGameConfigFile}, {"GameData.GetOffset", smn_GameConfGetOffset}, {"GameData.GetKeyValue", smn_GameConfGetKeyValue}, + {"GameData.GetAddressEx", smn_GameConfGetAddressEx}, + {"GameData.GetMemSigEx", smn_GameConfGetMemSigEx}, + + // Deprecated {"GameData.GetAddress", smn_GameConfGetAddress}, {"GameData.GetMemSig", smn_GameConfGetMemSig}, {NULL, NULL} diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index 929b4a4a8f..49c5704eb2 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -35,6 +35,7 @@ #include "PlayerManager.h" #include "HalfLife2.h" #include +#include #include "sm_stringutil.h" #include "logic_bridge.h" @@ -76,6 +77,44 @@ // Not defined in the sdk as we have no clue what it is #define FL_EP2V_UNKNOWN (1 << 2) +HandleType_t g_MemoryPtr = 0; + +class SimpleMemoryPointer : IMemoryPointer +{ +public: + SimpleMemoryPointer(void* ptr) : m_ptr(ptr) + { + } + + virtual void Delete() + { + delete this; + } + + virtual cell_t GetSize() override + { + return 0; + } + + virtual void* Get() override + { + return m_ptr; + } +protected: + void* m_ptr; +}; + +class EntitiesHelpers : + public SMGlobalClass +{ +public: + virtual void OnSourceModAllInitialized_Post() + { + // This should never fail + handlesys->FindHandleType("MemoryPointer", &g_MemoryPtr); + } +} s_ConsoleHelpers; + enum PropType { Prop_Send = 0, @@ -2779,6 +2818,87 @@ static cell_t GetEntityAddress(IPluginContext *pContext, const cell_t *params) #endif } +static cell_t GetEntityMemoryPointer(IPluginContext *pContext, const cell_t *params) +{ + CBaseEntity * pEntity = GetEntity(params[1]); + if (!pEntity) + { + return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[1]), params[1]); + } + + + auto newPtr = new SimpleMemoryPointer(pEntity); + Handle_t newHandle = handlesys->CreateHandle(g_MemoryPtr, newPtr, pContext->GetIdentity(), g_pCoreIdent, NULL); + if (newHandle == BAD_HANDLE) + { + delete newPtr; + return BAD_HANDLE; + } + return newHandle; +} + +static cell_t MemoryPointer_StoreEntityToHandle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMemoryPointer *ptr; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + CBaseHandle &entityHandle = *reinterpret_cast(((intptr_t)ptr->Get()) + params[3]); + + if ((unsigned)params[2] == INVALID_EHANDLE_INDEX) + { + entityHandle.Set(NULL); + } + else + { + CBaseEntity *pOther = GetEntity(params[2]); + + if (!pOther) + { + return pContext->ThrowNativeError("Entity %d (%d) is invalid", g_HL2.ReferenceToIndex(params[2]), params[2]); + } + + IHandleEntity *pHandleEnt = (IHandleEntity *)pOther; + entityHandle.Set(pHandleEnt); + } + return 0; +} + +static cell_t MemoryPointer_LoadEntityFromHandle(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = (Handle_t)params[1]; + HandleError err; + IMemoryPointer *ptr; + + HandleSecurity sec; + sec.pIdentity = g_pCoreIdent; + sec.pOwner = pContext->GetIdentity(); + + if ((err=handlesys->ReadHandle(hndl, g_MemoryPtr, &sec, (void **)&ptr)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err); + } + + CBaseHandle &entityHandle = *reinterpret_cast(((intptr_t)ptr->Get()) + params[2]); + CBaseEntity *pHandleEntity = g_HL2.ReferenceToEntity(entityHandle.GetEntryIndex()); + + if (!pHandleEntity || entityHandle != reinterpret_cast(pHandleEntity)->GetRefEHandle()) + { + return -1; + } + + return g_HL2.EntityToBCompatRef(pHandleEntity); +} + REGISTER_NATIVES(entityNatives) { {"ChangeEdictState", ChangeEdictState}, @@ -2823,8 +2943,11 @@ REGISTER_NATIVES(entityNatives) {"SetEntPropString", SetEntPropString}, {"SetEntPropVector", SetEntPropVector}, {"GetEntityAddress", GetEntityAddress}, + {"GetEntityMemoryPointer", GetEntityMemoryPointer}, {"FindDataMapInfo", FindDataMapInfo}, {"LoadEntityFromHandleAddress", LoadEntityFromHandleAddress}, {"StoreEntityToHandleAddress", StoreEntityToHandleAddress}, + {"MemoryPointer.StoreEntityToHandle", MemoryPointer_StoreEntityToHandle}, + {"MemoryPointer.LoadEntityFromHandle", MemoryPointer_LoadEntityFromHandle}, {NULL, NULL} }; diff --git a/extensions/sdktools/vcaller.cpp b/extensions/sdktools/vcaller.cpp index 7b11ecc732..3371454fdd 100644 --- a/extensions/sdktools/vcaller.cpp +++ b/extensions/sdktools/vcaller.cpp @@ -183,6 +183,25 @@ static cell_t PrepSDKCall_SetAddress(IPluginContext *pContext, const cell_t *par return (s_call_addr != NULL) ? 1 : 0; } +static cell_t PrepSDKCall_SetAddressFromMemoryPointer(IPluginContext *pContext, const cell_t *params) +{ + IMemoryPointer* memPtr = nullptr; + + HandleSecurity security; + security.pIdentity = myself->GetIdentity(); + security.pOwner = pContext->GetIdentity(); + + HandleError err = HandleError_None; + Handle_t hndl = (Handle_t)params[1]; + if ((err = handlesys->ReadHandle(hndl, g_MemPtrHandle, &security, (void **)&memPtr)) != HandleError_None) + { + return pContext->ThrowNativeError("Could not read MemoryPointer Handle %x (error %d)", hndl, err); + } + + s_call_addr = memPtr->Get(); + return (s_call_addr != NULL) ? 1 : 0; +} + // Must match same enum in sdktools.inc enum SDKFuncConfSource { @@ -597,6 +616,7 @@ sp_nativeinfo_t g_CallNatives[] = {"PrepSDKCall_SetVirtual", PrepSDKCall_SetVirtual}, {"PrepSDKCall_SetSignature", PrepSDKCall_SetSignature}, {"PrepSDKCall_SetAddress", PrepSDKCall_SetAddress}, + {"PrepSDKCall_SetAddressFromMemoryPointer", PrepSDKCall_SetAddressFromMemoryPointer}, {"PrepSDKCall_SetFromConf", PrepSDKCall_SetFromConf}, {"PrepSDKCall_SetReturnInfo", PrepSDKCall_SetReturnInfo}, {"PrepSDKCall_AddParameter", PrepSDKCall_AddParameter}, diff --git a/extensions/sdktools/vdecoder.cpp b/extensions/sdktools/vdecoder.cpp index 033ea7a19e..7110fe4fbd 100644 --- a/extensions/sdktools/vdecoder.cpp +++ b/extensions/sdktools/vdecoder.cpp @@ -46,6 +46,11 @@ class ForeignMemoryPointer : public IMemoryPointer { } + virtual void Delete() override + { + delete this; + } + virtual void* Get() override { return m_ptr; diff --git a/plugins/include/entity.inc b/plugins/include/entity.inc index 0bebb6a1a3..d48c9555c1 100644 --- a/plugins/include/entity.inc +++ b/plugins/include/entity.inc @@ -751,8 +751,18 @@ stock void SetEntDataArray(int entity, int offset, const any[] array, int arrayS * @return Address of the entity. * @error Invalid entity. */ +#pragma deprecated Use GetEntityMemoryPointer instead native Address GetEntityAddress(int entity); +/** + * Gets the memory address of an entity and wraps into a new MemoryPointer handle. + * + * @param entity Entity index. + * @return New MemoryPointer handle. + * @error Invalid entity. + */ +native MemoryPointer GetEntityMemoryPointer(int entity); + /** * Retrieves the classname of an entity. * This is like GetEdictClassname(), except it works for ALL @@ -774,6 +784,7 @@ stock bool GetEntityClassname(int entity, char[] clsname, int maxlength) * @param addr Address to a memory location. * @return Entity index at the given location. If there is no entity, or the stored entity is invalid, then -1 is returned. */ +#pragma deprecated Use MemoryPointer.LoadEntityFromHandle instead native int LoadEntityFromHandleAddress(Address addr); /** @@ -782,4 +793,5 @@ native int LoadEntityFromHandleAddress(Address addr); * @param addr Address to a memory location. * @param entity Entity index to set, or -1 to clear. */ +#pragma deprecated Use MemoryPointer.StoreEntityToHandle instead native void StoreEntityToHandleAddress(Address addr, int entity); diff --git a/plugins/include/sdktools.inc b/plugins/include/sdktools.inc index b5fb8e4e0c..92fb31a796 100644 --- a/plugins/include/sdktools.inc +++ b/plugins/include/sdktools.inc @@ -140,8 +140,18 @@ native bool PrepSDKCall_SetSignature(SDKLibrary lib, const char[] signature, int * @param addr Address of function to use. * @return True on success, false on failure. */ +#pragma deprecated Use PrepSDKCall_SetAddressFromMemoryPointer instead native bool PrepSDKCall_SetAddress(Address addr); +/** + * Uses the given pointer value as function address for the SDK call. + * + * @param handle Handle to a MemoryPointer. + * @return True on success, false on failure. + * @error Invalid handle. + */ +native bool PrepSDKCall_SetAddressFromMemoryPointer(MemoryPointer handle); + /** * Finds an address or virtual function index in a GameConfig file and sets it as * the calling information for the SDK call. diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index c033dabfbc..ffe68630bb 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -113,13 +113,28 @@ methodmap GameData < Handle // // @param name Name of the property to find. // @return An address calculated on success, or 0 on failure. + #pragma deprecated Use GameData.GetAddressEx instead public native Address GetAddress(const char[] name); + // Finds an address calculation in a GameConfig file, + // performs LoadFromAddress on it as appropriate, then returns the final address as a new MemoryPointer handle. + // + // @param name Name of the property to find. + // @return New MemoryPointer handle containing the address calculated on success, or null on failure. + public native Address GetAddressEx(const char[] name); + // Returns a function address calculated from a signature. // // @param name Name of the property to find. // @return An address calculated on success, or 0 on failure. + #pragma deprecated Use GameData.GetMemSigEx instead public native Address GetMemSig(const char[] name); + + // Returns a function address calculated from a signature as new MemoryPointer handle. + // + // @param name Name of the property to find. + // @return New MemoryPointer handle containing the address calculated on success, or null on failure. + public native Address GetMemSigEx(const char[] name); }; /** @@ -467,6 +482,7 @@ native bool GameConfGetKeyValue(Handle gc, const char[] key, char[] buffer, int * @param name Name of the property to find. * @return An address calculated on success, or 0 on failure. */ +#pragma deprecated Use GameData.GetAddressEx instead native Address GameConfGetAddress(Handle gameconf, const char[] name); /** @@ -739,6 +755,7 @@ enum Address * @return The value that is stored at that address. * @error Address is null or pointing to reserved memory. */ +#pragma deprecated Use MemoryPointer.Load instead native any LoadFromAddress(Address addr, NumberType size); /** @@ -752,6 +769,7 @@ native any LoadFromAddress(Address addr, NumberType size); * on the memory page being written to. * @error Address is null or pointing to reserved memory. */ +#pragma deprecated Use MemoryPointer.Store instead native void StoreToAddress(Address addr, any data, NumberType size, bool updateMemAccess = true); methodmap MemoryPointer < Handle { @@ -761,9 +779,11 @@ methodmap MemoryPointer < Handle { public native MemoryPointer(int size); // Stores the given data at the provided offset. - // @param data The data to store. - // @param size Size of the data to store. - // @param offset Offset in bytes from the start. + // @param data The data to store. + // @param size Size of the data to store. + // @param offset Offset in bytes from the start. + // @param updateMemAccess If true, SourceMod will set read / write / exec permissions + // on the memory page being written to. public native void Store(any data, NumberType size, int offset = 0, bool updateMemAccess = true); // Retrieves the data at the provided offset. @@ -771,6 +791,33 @@ methodmap MemoryPointer < Handle { // @param offset Offset in bytes from the start. // @return The data that was stored. public native any Load(NumberType size, int offset = 0); + + // Stores the given entity index into a CHandle at the provided offset. + // @param entity Entity index to store, -1 to clear. + // @param offset Offset in bytes from the start. + public native void StoreEntityToHandle(int entity, int offset = 0); + + // Retrieves the entity index from the CHandle at the provided offset. + // @param offset Offset in bytes from the start. + // @return Entity index at the given location. If there is no entity, or the stored entity is invalid, then -1 is returned. + public native int LoadEntityFromHandle(int offset = 0); + + // Stores a memory pointer at the provided offset. + // @param handle Handle to the memory pointer to store. + // @param offset Offset in bytes from the start. + // @param updateMemAccess If true, SourceMod will set read / write / exec permissions + // on the memory page being written to. + public native void StoreMemoryPointer(MemoryPointer handle, int offset = 0, bool updateMemAccess = true); + + // Wraps the data loaded at the provided offset into a new MemoryPointer handle. + // @param offset Offset in bytes from the start. + // @return New Handle to a memory pointer. + public native MemoryPointer LoadMemoryPointer(int offset = 0); + + // Creates a new MemoryPointer handle by offsetting the base pointer. + // @param size Offset from base pointer in bytes. + // @return New Handle to a memory pointer. + public native MemoryPointer Offset(int offset); }; methodmap FrameIterator < Handle { diff --git a/public/IMemoryPointer.h b/public/IMemoryPointer.h index a4683659c8..968dce1296 100644 --- a/public/IMemoryPointer.h +++ b/public/IMemoryPointer.h @@ -43,6 +43,11 @@ namespace SourceMod public: virtual ~IMemoryPointer() = default; + /** + * @brief Deletes the Memory pointer. + */ + virtual void Delete() = 0; + /** * @brief Retrieves the underlying pointer. * @@ -65,7 +70,7 @@ namespace SourceMod * @param offset Offset in bytes to store the data at. * @param updateMemAccess Whether or not to update the memory access before writing. */ - virtual void Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess); + void Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess); /** * @brief Loads data at the given offset. @@ -74,9 +79,44 @@ namespace SourceMod * @param offset Offset in bytes to read the data at. * @return The data stored at the given offset. */ - virtual cell_t Load(unsigned int byteSize, cell_t offset); + cell_t Load(unsigned int byteSize, cell_t offset); + + /** + * @brief Stores a pointer at the given offset. + * + * @param data The pointer to store. + * @param offset Offset in bytes to store the data at. + * @param updateMemAccess Whether or not to update the memory access before writing. + */ + void StorePtr(void* data, cell_t offset, bool updateMemAccess); + + /** + * @brief Loads pointer at the given offset. + * + * @param offset Offset in bytes to read the data at. + * @return The pointer stored at the given offset. + */ + void* LoadPtr(cell_t offset); }; + inline void IMemoryPointer::StorePtr(void* data, cell_t offset, bool updateMemAccess) + { + auto ptr = &(((std::int8_t*)this->Get())[offset]); + if (updateMemAccess) + { + SourceHook::SetMemAccess(ptr, sizeof(void*), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC); + } + + *(void**)ptr = data; + } + + inline void* IMemoryPointer::LoadPtr(cell_t offset) + { + auto ptr = &(((std::int8_t*)this->Get())[offset]); + + return *(void**)ptr; + } + inline void IMemoryPointer::Store(cell_t data, unsigned int byteSize, cell_t offset, bool updateMemAccess) { auto ptr = &(((std::int8_t*)this->Get())[offset]);