From bfcfbbe1071d0d26ab466606c7741f866d33454c Mon Sep 17 00:00:00 2001 From: Peace-Maker Date: Mon, 4 Aug 2014 02:05:25 +0200 Subject: [PATCH] Add WritePackFunction and ReadPackFunction natives Adds type safety to CDataPack. Cells can't be read as Float anymore. Now you're able to store a function pointer in a datapack and be sure the pointer can't be read as a cell and a cell can't be read as a function pointer. --- core/CDataPack.cpp | 94 ++++++++++++++++++++++++++++++++---- core/CDataPack.h | 10 ++++ core/logic/smn_datapacks.cpp | 51 ++++++++++++++++++- plugins/include/datapack.inc | 19 ++++++++ public/IDataPack.h | 14 ++++++ 5 files changed, 176 insertions(+), 12 deletions(-) diff --git a/core/CDataPack.cpp b/core/CDataPack.cpp index 59352c92..59b0bbc0 100644 --- a/core/CDataPack.cpp +++ b/core/CDataPack.cpp @@ -76,9 +76,12 @@ void CDataPack::ResetSize() size_t CDataPack::CreateMemory(size_t size, void **addr) { - CheckSize(sizeof(size_t) + size); + CheckSize(sizeof(char) + sizeof(size_t) + size); size_t pos = m_curptr - m_pBase; + *(char *)m_curptr = Raw; + m_curptr += sizeof(char); + *(size_t *)m_curptr = size; m_curptr += sizeof(size_t); @@ -88,14 +91,17 @@ size_t CDataPack::CreateMemory(size_t size, void **addr) } m_curptr += size; - m_size += sizeof(size_t) + size; + m_size += sizeof(char) + sizeof(size_t) + size; return pos; } void CDataPack::PackCell(cell_t cell) { - CheckSize(sizeof(size_t) + sizeof(cell_t)); + CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t)); + + *(char *)m_curptr = Cell; + m_curptr += sizeof(char); *(size_t *)m_curptr = sizeof(cell_t); m_curptr += sizeof(size_t); @@ -103,12 +109,15 @@ void CDataPack::PackCell(cell_t cell) *(cell_t *)m_curptr = cell; m_curptr += sizeof(cell_t); - m_size += sizeof(size_t) + sizeof(cell_t); + m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t); } void CDataPack::PackFloat(float val) { - CheckSize(sizeof(size_t) + sizeof(float)); + CheckSize(sizeof(char) + sizeof(size_t) + sizeof(float)); + + *(char *)m_curptr = Float; + m_curptr += sizeof(char); *(size_t *)m_curptr = sizeof(float); m_curptr += sizeof(size_t); @@ -116,15 +125,18 @@ void CDataPack::PackFloat(float val) *(float *)m_curptr = val; m_curptr += sizeof(float); - m_size += sizeof(size_t) + sizeof(float); + m_size += sizeof(char) + sizeof(size_t) + sizeof(float); } void CDataPack::PackString(const char *string) { size_t len = strlen(string); - size_t maxsize = sizeof(size_t) + len + 1; + size_t maxsize = sizeof(char) + sizeof(size_t) + len + 1; CheckSize(maxsize); + *(char *)m_curptr = String; + m_curptr += sizeof(char); + // Pack the string length first for buffer overrun checking. *(size_t *)m_curptr = len; m_curptr += sizeof(size_t); @@ -160,10 +172,16 @@ bool CDataPack::SetPosition(size_t pos) const cell_t CDataPack::ReadCell() const { - if (!IsReadable(sizeof(size_t) + sizeof(cell_t))) + if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t))) { return 0; } + if (*reinterpret_cast(m_curptr) != Cell) + { + return 0; + } + m_curptr += sizeof(char); + if (*reinterpret_cast(m_curptr) != sizeof(cell_t)) { return 0; @@ -178,10 +196,16 @@ cell_t CDataPack::ReadCell() const float CDataPack::ReadFloat() const { - if (!IsReadable(sizeof(size_t) + sizeof(float))) + if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float))) { return 0; } + if (*reinterpret_cast(m_curptr) != Float) + { + return 0; + } + m_curptr += sizeof(char); + if (*reinterpret_cast(m_curptr) != sizeof(float)) { return 0; @@ -201,10 +225,15 @@ bool CDataPack::IsReadable(size_t bytes) const const char *CDataPack::ReadString(size_t *len) const { - if (!IsReadable(sizeof(size_t))) + if (!IsReadable(sizeof(char) + sizeof(size_t))) { return NULL; } + if (*reinterpret_cast(m_curptr) != String) + { + return NULL; + } + m_curptr += sizeof(char); size_t real_len = *(size_t *)m_curptr; @@ -237,6 +266,11 @@ void *CDataPack::ReadMemory(size_t *size) const { return NULL; } + if (*reinterpret_cast(m_curptr) != Raw) + { + return NULL; + } + m_curptr += sizeof(char); size_t bytecount = *(size_t *)m_curptr; m_curptr += sizeof(size_t); @@ -257,3 +291,43 @@ void *CDataPack::ReadMemory(size_t *size) const return ptr; } + +void CDataPack::PackFunction(cell_t function) +{ + CheckSize(sizeof(char) + sizeof(size_t) + sizeof(cell_t)); + + *(char *)m_curptr = Function; + m_curptr += sizeof(char); + + *(size_t *)m_curptr = sizeof(cell_t); + m_curptr += sizeof(size_t); + + *(cell_t *)m_curptr = function; + m_curptr += sizeof(cell_t); + + m_size += sizeof(char) + sizeof(size_t) + sizeof(cell_t); +} + +cell_t CDataPack::ReadFunction() const +{ + if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t))) + { + return 0; + } + if (*reinterpret_cast(m_curptr) != Function) + { + return 0; + } + m_curptr += sizeof(char); + + if (*reinterpret_cast(m_curptr) != sizeof(cell_t)) + { + return 0; + } + + m_curptr += sizeof(size_t); + + cell_t val = *reinterpret_cast(m_curptr); + m_curptr += sizeof(cell_t); + return val; +} \ No newline at end of file diff --git a/core/CDataPack.h b/core/CDataPack.h index 83a53539..48883f0d 100644 --- a/core/CDataPack.h +++ b/core/CDataPack.h @@ -51,12 +51,14 @@ public: //IDataReader const char *ReadString(size_t *len) const; void *GetMemory() const; void *ReadMemory(size_t *size) const; + cell_t ReadFunction() const; public: //IDataPack void ResetSize(); void PackCell(cell_t cell); void PackFloat(float val); void PackString(const char *string); size_t CreateMemory(size_t size, void **addr); + void PackFunction(cell_t function); public: void Initialize(); private: @@ -66,6 +68,14 @@ private: mutable char *m_curptr; size_t m_capacity; size_t m_size; + + enum DataPackType { + Raw, + Cell, + Float, + String, + Function + }; }; #endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_ diff --git a/core/logic/smn_datapacks.cpp b/core/logic/smn_datapacks.cpp index 21d7e7d6..2612abbc 100644 --- a/core/logic/smn_datapacks.cpp +++ b/core/logic/smn_datapacks.cpp @@ -148,6 +148,27 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params return 1; } +static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + pDataPack->PackFunction(params[2]); + + return 1; +} + static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -164,7 +185,7 @@ static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); } - if (!pDataPack->IsReadable(sizeof(size_t) + sizeof(cell_t))) + if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t))) { return pContext->ThrowNativeError("DataPack operation is out of bounds."); } @@ -188,7 +209,7 @@ static cell_t smn_ReadPackFloat(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); } - if (!pDataPack->IsReadable(sizeof(size_t) + sizeof(float))) + if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float))) { return pContext->ThrowNativeError("DataPack operation is out of bounds."); } @@ -223,6 +244,30 @@ static cell_t smn_ReadPackString(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *params) +{ + Handle_t hndl = static_cast(params[1]); + HandleError herr; + HandleSecurity sec; + IDataPack *pDataPack; + + sec.pOwner = pContext->GetIdentity(); + sec.pIdentity = g_pCoreIdent; + + if ((herr = handlesys->ReadHandle(hndl, g_DataPackType, &sec, (void **)&pDataPack)) + != HandleError_None) + { + return pContext->ThrowNativeError("Invalid data pack handle %x (error %d)", hndl, herr); + } + + if (!pDataPack->IsReadable(sizeof(char) + sizeof(size_t) + sizeof(cell_t))) + { + return pContext->ThrowNativeError("DataPack operation is out of bounds."); + } + + return pDataPack->ReadFunction(); +} + static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params) { Handle_t hndl = static_cast(params[1]); @@ -318,9 +363,11 @@ REGISTER_NATIVES(datapacknatives) {"WritePackCell", smn_WritePackCell}, {"WritePackFloat", smn_WritePackFloat}, {"WritePackString", smn_WritePackString}, + {"WritePackFunction", smn_WritePackFunction}, {"ReadPackCell", smn_ReadPackCell}, {"ReadPackFloat", smn_ReadPackFloat}, {"ReadPackString", smn_ReadPackString}, + {"ReadPackFunction", smn_ReadPackFunction}, {"ResetPack", smn_ResetPack}, {"GetPackPosition", smn_GetPackPosition}, {"SetPackPosition", smn_SetPackPosition}, diff --git a/plugins/include/datapack.inc b/plugins/include/datapack.inc index 73c66ff6..8c3ab0e9 100644 --- a/plugins/include/datapack.inc +++ b/plugins/include/datapack.inc @@ -72,6 +72,16 @@ native WritePackFloat(Handle:pack, Float:val); */ native WritePackString(Handle:pack, const String:str[]); +/** + * Packs a function pointer into a data pack. + * + * @param pack Handle to the data pack. + * @param fktptr Function pointer to add. + * @noreturn + * @error Invalid handle. + */ +native WritePackFunction(Handle:pack, Function:fktptr); + /** * Reads a cell from a data pack. * @@ -101,6 +111,15 @@ native Float:ReadPackFloat(Handle:pack); */ native ReadPackString(Handle:pack, String:buffer[], maxlen); +/** + * Reads a function pointer from a data pack. + * + * @param pack Handle to the data pack. + * @return Function pointer. + * @error Invalid handle, or bounds error. + */ +native Function ReadPackFunction(Handle:pack); + /** * Resets the position in a data pack. * diff --git a/public/IDataPack.h b/public/IDataPack.h index a84a4416..e069bff0 100644 --- a/public/IDataPack.h +++ b/public/IDataPack.h @@ -113,6 +113,13 @@ namespace SourceMod * @return Pointer to the data, or NULL if out of bounds. */ virtual void *ReadMemory(size_t *size) const =0; + + /** + * @brief Reads a function pointer from the data stream. + * + * @return A function pointer read from the current position. + */ + virtual cell_t ReadFunction() const =0; }; /** @@ -160,6 +167,13 @@ namespace SourceMod * @return Current position of the stream beforehand. */ virtual size_t CreateMemory(size_t size, void **addr) =0; + + /** + * @brief Packs one function pointer into the data stream. + * + * @param function The function pointer to write. + */ + virtual void PackFunction(cell_t function) =0; }; }