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.
This commit is contained in:
Peace-Maker 2014-08-04 02:05:25 +02:00
parent 836cde4e21
commit bfcfbbe107
5 changed files with 176 additions and 12 deletions

View File

@ -76,9 +76,12 @@ void CDataPack::ResetSize()
size_t CDataPack::CreateMemory(size_t size, void **addr) 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; size_t pos = m_curptr - m_pBase;
*(char *)m_curptr = Raw;
m_curptr += sizeof(char);
*(size_t *)m_curptr = size; *(size_t *)m_curptr = size;
m_curptr += sizeof(size_t); m_curptr += sizeof(size_t);
@ -88,14 +91,17 @@ size_t CDataPack::CreateMemory(size_t size, void **addr)
} }
m_curptr += size; m_curptr += size;
m_size += sizeof(size_t) + size; m_size += sizeof(char) + sizeof(size_t) + size;
return pos; return pos;
} }
void CDataPack::PackCell(cell_t cell) 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); *(size_t *)m_curptr = sizeof(cell_t);
m_curptr += sizeof(size_t); m_curptr += sizeof(size_t);
@ -103,12 +109,15 @@ void CDataPack::PackCell(cell_t cell)
*(cell_t *)m_curptr = cell; *(cell_t *)m_curptr = cell;
m_curptr += sizeof(cell_t); 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) 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); *(size_t *)m_curptr = sizeof(float);
m_curptr += sizeof(size_t); m_curptr += sizeof(size_t);
@ -116,15 +125,18 @@ void CDataPack::PackFloat(float val)
*(float *)m_curptr = val; *(float *)m_curptr = val;
m_curptr += sizeof(float); 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) void CDataPack::PackString(const char *string)
{ {
size_t len = strlen(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); CheckSize(maxsize);
*(char *)m_curptr = String;
m_curptr += sizeof(char);
// Pack the string length first for buffer overrun checking. // Pack the string length first for buffer overrun checking.
*(size_t *)m_curptr = len; *(size_t *)m_curptr = len;
m_curptr += sizeof(size_t); m_curptr += sizeof(size_t);
@ -160,10 +172,16 @@ bool CDataPack::SetPosition(size_t pos) const
cell_t CDataPack::ReadCell() 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; return 0;
} }
if (*reinterpret_cast<char *>(m_curptr) != Cell)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t)) if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{ {
return 0; return 0;
@ -178,10 +196,16 @@ cell_t CDataPack::ReadCell() const
float CDataPack::ReadFloat() const float CDataPack::ReadFloat() const
{ {
if (!IsReadable(sizeof(size_t) + sizeof(float))) if (!IsReadable(sizeof(char) + sizeof(size_t) + sizeof(float)))
{ {
return 0; return 0;
} }
if (*reinterpret_cast<char *>(m_curptr) != Float)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float)) if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(float))
{ {
return 0; return 0;
@ -201,10 +225,15 @@ bool CDataPack::IsReadable(size_t bytes) const
const char *CDataPack::ReadString(size_t *len) const const char *CDataPack::ReadString(size_t *len) const
{ {
if (!IsReadable(sizeof(size_t))) if (!IsReadable(sizeof(char) + sizeof(size_t)))
{ {
return NULL; return NULL;
} }
if (*reinterpret_cast<char *>(m_curptr) != String)
{
return NULL;
}
m_curptr += sizeof(char);
size_t real_len = *(size_t *)m_curptr; size_t real_len = *(size_t *)m_curptr;
@ -237,6 +266,11 @@ void *CDataPack::ReadMemory(size_t *size) const
{ {
return NULL; return NULL;
} }
if (*reinterpret_cast<char *>(m_curptr) != Raw)
{
return NULL;
}
m_curptr += sizeof(char);
size_t bytecount = *(size_t *)m_curptr; size_t bytecount = *(size_t *)m_curptr;
m_curptr += sizeof(size_t); m_curptr += sizeof(size_t);
@ -257,3 +291,43 @@ void *CDataPack::ReadMemory(size_t *size) const
return ptr; 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<char *>(m_curptr) != Function)
{
return 0;
}
m_curptr += sizeof(char);
if (*reinterpret_cast<size_t *>(m_curptr) != sizeof(cell_t))
{
return 0;
}
m_curptr += sizeof(size_t);
cell_t val = *reinterpret_cast<cell_t *>(m_curptr);
m_curptr += sizeof(cell_t);
return val;
}

View File

@ -51,12 +51,14 @@ public: //IDataReader
const char *ReadString(size_t *len) const; const char *ReadString(size_t *len) const;
void *GetMemory() const; void *GetMemory() const;
void *ReadMemory(size_t *size) const; void *ReadMemory(size_t *size) const;
cell_t ReadFunction() const;
public: //IDataPack public: //IDataPack
void ResetSize(); void ResetSize();
void PackCell(cell_t cell); void PackCell(cell_t cell);
void PackFloat(float val); void PackFloat(float val);
void PackString(const char *string); void PackString(const char *string);
size_t CreateMemory(size_t size, void **addr); size_t CreateMemory(size_t size, void **addr);
void PackFunction(cell_t function);
public: public:
void Initialize(); void Initialize();
private: private:
@ -66,6 +68,14 @@ private:
mutable char *m_curptr; mutable char *m_curptr;
size_t m_capacity; size_t m_capacity;
size_t m_size; size_t m_size;
enum DataPackType {
Raw,
Cell,
Float,
String,
Function
};
}; };
#endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_ #endif //_INCLUDE_SOURCEMOD_CDATAPACK_H_

View File

@ -148,6 +148,27 @@ static cell_t smn_WritePackString(IPluginContext *pContext, const cell_t *params
return 1; return 1;
} }
static cell_t smn_WritePackFunction(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(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) static cell_t smn_ReadPackCell(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl = static_cast<Handle_t>(params[1]); Handle_t hndl = static_cast<Handle_t>(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); 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."); 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); 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."); 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; return 1;
} }
static cell_t smn_ReadPackFunction(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(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) static cell_t smn_ResetPack(IPluginContext *pContext, const cell_t *params)
{ {
Handle_t hndl = static_cast<Handle_t>(params[1]); Handle_t hndl = static_cast<Handle_t>(params[1]);
@ -318,9 +363,11 @@ REGISTER_NATIVES(datapacknatives)
{"WritePackCell", smn_WritePackCell}, {"WritePackCell", smn_WritePackCell},
{"WritePackFloat", smn_WritePackFloat}, {"WritePackFloat", smn_WritePackFloat},
{"WritePackString", smn_WritePackString}, {"WritePackString", smn_WritePackString},
{"WritePackFunction", smn_WritePackFunction},
{"ReadPackCell", smn_ReadPackCell}, {"ReadPackCell", smn_ReadPackCell},
{"ReadPackFloat", smn_ReadPackFloat}, {"ReadPackFloat", smn_ReadPackFloat},
{"ReadPackString", smn_ReadPackString}, {"ReadPackString", smn_ReadPackString},
{"ReadPackFunction", smn_ReadPackFunction},
{"ResetPack", smn_ResetPack}, {"ResetPack", smn_ResetPack},
{"GetPackPosition", smn_GetPackPosition}, {"GetPackPosition", smn_GetPackPosition},
{"SetPackPosition", smn_SetPackPosition}, {"SetPackPosition", smn_SetPackPosition},

View File

@ -72,6 +72,16 @@ native WritePackFloat(Handle:pack, Float:val);
*/ */
native WritePackString(Handle:pack, const String:str[]); 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. * Reads a cell from a data pack.
* *
@ -101,6 +111,15 @@ native Float:ReadPackFloat(Handle:pack);
*/ */
native ReadPackString(Handle:pack, String:buffer[], maxlen); 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. * Resets the position in a data pack.
* *

View File

@ -113,6 +113,13 @@ namespace SourceMod
* @return Pointer to the data, or NULL if out of bounds. * @return Pointer to the data, or NULL if out of bounds.
*/ */
virtual void *ReadMemory(size_t *size) const =0; 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. * @return Current position of the stream beforehand.
*/ */
virtual size_t CreateMemory(size_t size, void **addr) =0; 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;
}; };
} }