From 163098892c0f0315ece9d89667782fd0ad53f3ca Mon Sep 17 00:00:00 2001 From: Nextra Date: Sat, 27 Jul 2013 20:49:19 +0200 Subject: [PATCH] Fix re-entrancy issue when a [generated] message is sent during register_event forward (bug 3664, r=joropito) --- amxmodx/CEvent.cpp | 125 +++++++++++++++++++++++++----------- amxmodx/CEvent.h | 6 +- amxmodx/amxmodx.cpp | 7 ++ plugins/include/amxmodx.inc | 3 + 4 files changed, 104 insertions(+), 37 deletions(-) diff --git a/amxmodx/CEvent.cpp b/amxmodx/CEvent.cpp index 3de6fd39..4ae1cb57 100755 --- a/amxmodx/CEvent.cpp +++ b/amxmodx/CEvent.cpp @@ -55,16 +55,16 @@ EventsMngr::ClEvent::ClEvent(CPluginMngr::CPlugin* plugin, int func, int flags) m_FlagDead = (flags & 8) ? true : false; // flag d } - if (m_FlagClient) - { - m_FlagPlayer = true; - m_FlagBot = true; - - if (flags & 96) - { - m_FlagPlayer = (flags & 32) ? true : false; // flag f - m_FlagBot = (flags & 64) ? true : false; // flag g - } + if (m_FlagClient) + { + m_FlagPlayer = true; + m_FlagBot = true; + + if (flags & 96) + { + m_FlagPlayer = (flags & 32) ? true : false; // flag f + m_FlagBot = (flags & 64) ? true : false; // flag g + } } m_Stamp = 0.0f; @@ -138,7 +138,11 @@ EventsMngr::EventsMngr() { m_ParseVault = NULL; m_ParseVaultSize = 0; - m_CurrentMsgType = -1; + m_ParseMsgType = -1; + m_ReadVault = NULL; + m_ReadVaultSize = 0; + m_ReadPos = -1; + m_ReadMsgType = -1; clearEvents(); } @@ -227,15 +231,15 @@ void EventsMngr::parserInit(int msg_type, float* timer, CPlayer* pPlayer, int in if (msg_type < 0 || msg_type > MAX_AMX_REG_MSG) return; - m_CurrentMsgType = msg_type; - m_ParseNotDone = false; - m_Timer = timer; // don't parse if nothing to do if (!m_Events[msg_type].size()) return; + m_ParseMsgType = msg_type; + m_Timer = timer; + for (ClEventVecIter iter = m_Events[msg_type].begin(); iter; ++iter) { if ((*iter).m_Done) @@ -423,12 +427,46 @@ void EventsMngr::parseValue(const char *sz) void EventsMngr::executeEvents() { + static unsigned int reentrant = 0; if (!m_ParseFun) { return; } - for (ClEventVecIter iter = m_ParseFun->begin(); iter; ++iter) + // Store old read data, which are either default values or previous event data + int oldMsgType = m_ReadMsgType, oldReadPos = m_ReadPos; + MsgDataEntry *oldReadVault = m_ReadVault, *readVault = NULL; + + // We have a re-entrant call + if (reentrant++) + { + // Create temporary read vault + readVault = new MsgDataEntry[m_ParsePos + 1]; + m_ReadVault = readVault; + } else if (m_ReadVaultSize != m_ParseVaultSize) { + // Extend read vault size if necessary + delete [] m_ReadVault; + m_ReadVault = new MsgDataEntry[m_ParseVaultSize]; + m_ReadVaultSize = m_ParseVaultSize; + + // Update old read vault so we don't restore to a wrong pointer + oldReadVault = m_ReadVault; + } + + // Copy data over to readvault + m_ReadPos = m_ParsePos; + m_ReadMsgType = m_ParseMsgType; + + if (m_ParseVault) + { + memcpy(m_ReadVault, m_ParseVault, (m_ParsePos + 1) * sizeof(MsgDataEntry)); + } + + // Reset this here so we don't trigger re-entrancy for unregistered messages + ClEventVec *parseFun = m_ParseFun; + m_ParseFun = NULL; + + for (ClEventVecIter iter = parseFun->begin(); iter; ++iter) { if ((*iter).m_Done) { @@ -437,67 +475,74 @@ void EventsMngr::executeEvents() } (*iter).m_Stamp = (float)*m_Timer; - executeForwards((*iter).m_Func, static_cast(m_ParseVault ? m_ParseVault[0].iValue : 0)); - } - m_CurrentMsgType = -1; - m_ParseFun = NULL; + executeForwards((*iter).m_Func, static_cast(m_ReadVault ? m_ReadVault[0].iValue : 0)); + } + + // Restore old read data, either resetting to default or to previous event data + m_ReadMsgType = oldMsgType; + m_ReadPos = oldReadPos; + m_ReadVault = oldReadVault; + + delete [] readVault; + + --reentrant; } int EventsMngr::getArgNum() const { - return m_ParsePos + 1; + return m_ReadPos + 1; } const char* EventsMngr::getArgString(int a) const { - if (a < 0 || a > m_ParsePos) + if (a < 0 || a > m_ReadPos) return ""; static char var[32]; - switch (m_ParseVault[a].type) + switch (m_ReadVault[a].type) { case MSG_INTEGER: - sprintf(var, "%d", m_ParseVault[a].iValue); + sprintf(var, "%d", m_ReadVault[a].iValue); return var; case MSG_STRING: - return m_ParseVault[a].sValue; + return m_ReadVault[a].sValue; default: - sprintf(var, "%g", m_ParseVault[a].fValue); + sprintf(var, "%g", m_ReadVault[a].fValue); return var; } } int EventsMngr::getArgInteger(int a) const { - if (a < 0 || a > m_ParsePos) + if (a < 0 || a > m_ReadPos) return 0; - switch (m_ParseVault[a].type) + switch (m_ReadVault[a].type) { case MSG_INTEGER: - return m_ParseVault[a].iValue; + return m_ReadVault[a].iValue; case MSG_STRING: - return atoi(m_ParseVault[a].sValue); + return atoi(m_ReadVault[a].sValue); default: - return (int)m_ParseVault[a].fValue; + return (int)m_ReadVault[a].fValue; } } float EventsMngr::getArgFloat(int a) const { - if (a < 0 || a > m_ParsePos) + if (a < 0 || a > m_ReadPos) return 0.0f; - switch (m_ParseVault[a].type) + switch (m_ReadVault[a].type) { case MSG_INTEGER: - return static_cast(m_ParseVault[a].iValue); + return static_cast(m_ReadVault[a].iValue); case MSG_STRING: - return static_cast(atof(m_ParseVault[a].sValue)); + return static_cast(atof(m_ReadVault[a].sValue)); default: - return m_ParseVault[a].fValue; + return m_ReadVault[a].fValue; } } @@ -515,6 +560,14 @@ void EventsMngr::clearEvents(void) m_ParseVault = NULL; m_ParseVaultSize = 0; } + + if (m_ReadVault) + { + delete [] m_ReadVault; + m_ReadVault = NULL; + m_ReadVaultSize = 0; + m_ReadPos = -1; + } } int EventsMngr::getEventId(const char* msg) @@ -550,5 +603,5 @@ int EventsMngr::getEventId(const char* msg) int EventsMngr::getCurrentMsgType() { - return m_CurrentMsgType; + return m_ReadMsgType; } diff --git a/amxmodx/CEvent.h b/amxmodx/CEvent.h index 422920d6..0dbf7afb 100755 --- a/amxmodx/CEvent.h +++ b/amxmodx/CEvent.h @@ -121,7 +121,9 @@ private: }; MsgDataEntry *m_ParseVault; + MsgDataEntry *m_ReadVault; int m_ParseVaultSize; + int m_ReadVaultSize; void NextParam(); // make sure a new parameter can be added typedef CList ClEventVec; @@ -132,11 +134,13 @@ private: bool m_ParseNotDone; int m_ParsePos; // is args. num. - 1 + int m_ReadPos; float* m_Timer; ClEvent* getValidEvent(ClEvent* a); - int m_CurrentMsgType; + int m_ParseMsgType; + int m_ReadMsgType; public: EventsMngr(); ~EventsMngr(); diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 02a2fde8..43787912 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -2036,6 +2036,11 @@ static cell AMX_NATIVE_CALL read_data(AMX *amx, cell *params) /* 3 param */ } } +static cell AMX_NATIVE_CALL read_datatype(AMX *amx, cell *params) /* 0 param */ +{ + return g_events.getCurrentMsgType(); +} + static cell AMX_NATIVE_CALL get_playersnum(AMX *amx, cell *params) { if (!params[1]) @@ -4622,6 +4627,7 @@ static cell AMX_NATIVE_CALL is_rukia_a_hag(AMX *amx, cell *params) { return 1; }; + AMX_NATIVE_INFO amxmodx_Natives[] = { {"abort", amx_abort}, @@ -4762,6 +4768,7 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"read_argv", read_argv}, {"read_data", read_data}, {"read_datanum", read_datanum}, + {"read_datatype", read_datatype}, {"read_flags", read_flags}, {"read_logargc", read_logargc}, {"read_logargv", read_logargv}, diff --git a/plugins/include/amxmodx.inc b/plugins/include/amxmodx.inc index 0a08f5dc..4541e33d 100755 --- a/plugins/include/amxmodx.inc +++ b/plugins/include/amxmodx.inc @@ -162,6 +162,9 @@ native read_data(value, any:... ); /* Returns number of values in client message. */ native read_datanum(); +/* Returns message id of client message */ +native read_datatype(); + /* Gets log message. Can be called only in plugin_log() forward function. */ native read_logdata(output[],len);