Fix re-entrancy issue when a [generated] message is sent during register_event forward (bug 3664, r=joropito)

This commit is contained in:
Nextra 2013-07-27 20:49:19 +02:00
parent efe3bda51b
commit 163098892c
4 changed files with 104 additions and 37 deletions

View File

@ -138,7 +138,11 @@ EventsMngr::EventsMngr()
{ {
m_ParseVault = NULL; m_ParseVault = NULL;
m_ParseVaultSize = 0; m_ParseVaultSize = 0;
m_CurrentMsgType = -1; m_ParseMsgType = -1;
m_ReadVault = NULL;
m_ReadVaultSize = 0;
m_ReadPos = -1;
m_ReadMsgType = -1;
clearEvents(); 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) if (msg_type < 0 || msg_type > MAX_AMX_REG_MSG)
return; return;
m_CurrentMsgType = msg_type;
m_ParseNotDone = false; m_ParseNotDone = false;
m_Timer = timer;
// don't parse if nothing to do // don't parse if nothing to do
if (!m_Events[msg_type].size()) if (!m_Events[msg_type].size())
return; return;
m_ParseMsgType = msg_type;
m_Timer = timer;
for (ClEventVecIter iter = m_Events[msg_type].begin(); iter; ++iter) for (ClEventVecIter iter = m_Events[msg_type].begin(); iter; ++iter)
{ {
if ((*iter).m_Done) if ((*iter).m_Done)
@ -423,12 +427,46 @@ void EventsMngr::parseValue(const char *sz)
void EventsMngr::executeEvents() void EventsMngr::executeEvents()
{ {
static unsigned int reentrant = 0;
if (!m_ParseFun) if (!m_ParseFun)
{ {
return; 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) if ((*iter).m_Done)
{ {
@ -437,67 +475,74 @@ void EventsMngr::executeEvents()
} }
(*iter).m_Stamp = (float)*m_Timer; (*iter).m_Stamp = (float)*m_Timer;
executeForwards((*iter).m_Func, static_cast<cell>(m_ParseVault ? m_ParseVault[0].iValue : 0));
executeForwards((*iter).m_Func, static_cast<cell>(m_ReadVault ? m_ReadVault[0].iValue : 0));
} }
m_CurrentMsgType = -1; // Restore old read data, either resetting to default or to previous event data
m_ParseFun = NULL; m_ReadMsgType = oldMsgType;
m_ReadPos = oldReadPos;
m_ReadVault = oldReadVault;
delete [] readVault;
--reentrant;
} }
int EventsMngr::getArgNum() const int EventsMngr::getArgNum() const
{ {
return m_ParsePos + 1; return m_ReadPos + 1;
} }
const char* EventsMngr::getArgString(int a) const const char* EventsMngr::getArgString(int a) const
{ {
if (a < 0 || a > m_ParsePos) if (a < 0 || a > m_ReadPos)
return ""; return "";
static char var[32]; static char var[32];
switch (m_ParseVault[a].type) switch (m_ReadVault[a].type)
{ {
case MSG_INTEGER: case MSG_INTEGER:
sprintf(var, "%d", m_ParseVault[a].iValue); sprintf(var, "%d", m_ReadVault[a].iValue);
return var; return var;
case MSG_STRING: case MSG_STRING:
return m_ParseVault[a].sValue; return m_ReadVault[a].sValue;
default: default:
sprintf(var, "%g", m_ParseVault[a].fValue); sprintf(var, "%g", m_ReadVault[a].fValue);
return var; return var;
} }
} }
int EventsMngr::getArgInteger(int a) const int EventsMngr::getArgInteger(int a) const
{ {
if (a < 0 || a > m_ParsePos) if (a < 0 || a > m_ReadPos)
return 0; return 0;
switch (m_ParseVault[a].type) switch (m_ReadVault[a].type)
{ {
case MSG_INTEGER: case MSG_INTEGER:
return m_ParseVault[a].iValue; return m_ReadVault[a].iValue;
case MSG_STRING: case MSG_STRING:
return atoi(m_ParseVault[a].sValue); return atoi(m_ReadVault[a].sValue);
default: default:
return (int)m_ParseVault[a].fValue; return (int)m_ReadVault[a].fValue;
} }
} }
float EventsMngr::getArgFloat(int a) const float EventsMngr::getArgFloat(int a) const
{ {
if (a < 0 || a > m_ParsePos) if (a < 0 || a > m_ReadPos)
return 0.0f; return 0.0f;
switch (m_ParseVault[a].type) switch (m_ReadVault[a].type)
{ {
case MSG_INTEGER: case MSG_INTEGER:
return static_cast<float>(m_ParseVault[a].iValue); return static_cast<float>(m_ReadVault[a].iValue);
case MSG_STRING: case MSG_STRING:
return static_cast<float>(atof(m_ParseVault[a].sValue)); return static_cast<float>(atof(m_ReadVault[a].sValue));
default: default:
return m_ParseVault[a].fValue; return m_ReadVault[a].fValue;
} }
} }
@ -515,6 +560,14 @@ void EventsMngr::clearEvents(void)
m_ParseVault = NULL; m_ParseVault = NULL;
m_ParseVaultSize = 0; m_ParseVaultSize = 0;
} }
if (m_ReadVault)
{
delete [] m_ReadVault;
m_ReadVault = NULL;
m_ReadVaultSize = 0;
m_ReadPos = -1;
}
} }
int EventsMngr::getEventId(const char* msg) int EventsMngr::getEventId(const char* msg)
@ -550,5 +603,5 @@ int EventsMngr::getEventId(const char* msg)
int EventsMngr::getCurrentMsgType() int EventsMngr::getCurrentMsgType()
{ {
return m_CurrentMsgType; return m_ReadMsgType;
} }

View File

@ -121,7 +121,9 @@ private:
}; };
MsgDataEntry *m_ParseVault; MsgDataEntry *m_ParseVault;
MsgDataEntry *m_ReadVault;
int m_ParseVaultSize; int m_ParseVaultSize;
int m_ReadVaultSize;
void NextParam(); // make sure a new parameter can be added void NextParam(); // make sure a new parameter can be added
typedef CList<ClEvent> ClEventVec; typedef CList<ClEvent> ClEventVec;
@ -132,11 +134,13 @@ private:
bool m_ParseNotDone; bool m_ParseNotDone;
int m_ParsePos; // is args. num. - 1 int m_ParsePos; // is args. num. - 1
int m_ReadPos;
float* m_Timer; float* m_Timer;
ClEvent* getValidEvent(ClEvent* a); ClEvent* getValidEvent(ClEvent* a);
int m_CurrentMsgType; int m_ParseMsgType;
int m_ReadMsgType;
public: public:
EventsMngr(); EventsMngr();
~EventsMngr(); ~EventsMngr();

View File

@ -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) static cell AMX_NATIVE_CALL get_playersnum(AMX *amx, cell *params)
{ {
if (!params[1]) if (!params[1])
@ -4622,6 +4627,7 @@ static cell AMX_NATIVE_CALL is_rukia_a_hag(AMX *amx, cell *params)
{ {
return 1; return 1;
}; };
AMX_NATIVE_INFO amxmodx_Natives[] = AMX_NATIVE_INFO amxmodx_Natives[] =
{ {
{"abort", amx_abort}, {"abort", amx_abort},
@ -4762,6 +4768,7 @@ AMX_NATIVE_INFO amxmodx_Natives[] =
{"read_argv", read_argv}, {"read_argv", read_argv},
{"read_data", read_data}, {"read_data", read_data},
{"read_datanum", read_datanum}, {"read_datanum", read_datanum},
{"read_datatype", read_datatype},
{"read_flags", read_flags}, {"read_flags", read_flags},
{"read_logargc", read_logargc}, {"read_logargc", read_logargc},
{"read_logargv", read_logargv}, {"read_logargv", read_logargv},

View File

@ -162,6 +162,9 @@ native read_data(value, any:... );
/* Returns number of values in client message. */ /* Returns number of values in client message. */
native read_datanum(); native read_datanum();
/* Returns message id of client message */
native read_datatype();
/* Gets log message. Can be called only in plugin_log() forward function. */ /* Gets log message. Can be called only in plugin_log() forward function. */
native read_logdata(output[],len); native read_logdata(output[],len);