Fix an invalid pointer dereferencing issue in the script events system.

Closes #2300.
master
safety0ff 2010-11-20 21:18:58 -05:00
parent 16681df600
commit 8c9e7d5bd0
2 changed files with 73 additions and 64 deletions

View File

@ -43,7 +43,6 @@ static ACTIVE_TRIGGER *psAddedTriggers = NULL;
/** The trigger which is currently firing */ /** The trigger which is currently firing */
static ACTIVE_TRIGGER *psFiringTrigger = NULL; static ACTIVE_TRIGGER *psFiringTrigger = NULL;
static BOOL triggerChanged;
static UDWORD updateTime; static UDWORD updateTime;
/** The currently allocated contexts */ /** The currently allocated contexts */
@ -98,6 +97,15 @@ static void eventAddTrigger(ACTIVE_TRIGGER *psTrigger);
// Free up a trigger // Free up a trigger
static void eventFreeTrigger(ACTIVE_TRIGGER *psTrigger); static void eventFreeTrigger(ACTIVE_TRIGGER *psTrigger);
// Remove triggers marked for deletion
static void eventPruneList(ACTIVE_TRIGGER **psList);
static void eventPruneLists(void)
{
eventPruneList(&psTrigList);
eventPruneList(&psCallbackList);
eventPruneList(&psAddedTriggers);
}
//resets the event timer - updateTime //resets the event timer - updateTime
void eventTimeReset(UDWORD initTime) void eventTimeReset(UDWORD initTime)
{ {
@ -834,10 +842,8 @@ static BOOL eventInitTrigger(ACTIVE_TRIGGER **ppsTrigger, SCRIPT_CONTEXT *psCont
TRIGGER_DATA *psTrigData; TRIGGER_DATA *psTrigData;
UDWORD testTime; UDWORD testTime;
ASSERT( event < psContext->psCode->numEvents, ASSERT( event < psContext->psCode->numEvents, "Event out of range" );
"eventAddTrigger: Event out of range" ); ASSERT( trigger < psContext->psCode->numTriggers, "Trigger out of range" );
ASSERT( trigger < psContext->psCode->numTriggers,
"eventAddTrigger: Trigger out of range" );
if (trigger == -1) if (trigger == -1)
{ {
return false; return false;
@ -861,6 +867,7 @@ static BOOL eventInitTrigger(ACTIVE_TRIGGER **ppsTrigger, SCRIPT_CONTEXT *psCont
psNewTrig->type = (SWORD)psTrigData->type; psNewTrig->type = (SWORD)psTrigData->type;
psNewTrig->event = (UWORD)event; psNewTrig->event = (UWORD)event;
psNewTrig->offset = 0; psNewTrig->offset = 0;
psNewTrig->deactivated = false;
*ppsTrigger = psNewTrig; *ppsTrigger = psNewTrig;
@ -897,6 +904,7 @@ BOOL eventLoadTrigger(UDWORD time, SCRIPT_CONTEXT *psContext,
psNewTrig->type = (SWORD)type; psNewTrig->type = (SWORD)type;
psNewTrig->event = (UWORD)event; psNewTrig->event = (UWORD)event;
psNewTrig->offset = (UWORD)offset; psNewTrig->offset = (UWORD)offset;
psNewTrig->deactivated = false;
eventAddTrigger(psNewTrig); eventAddTrigger(psNewTrig);
@ -947,13 +955,14 @@ BOOL eventAddPauseTrigger(SCRIPT_CONTEXT *psContext, UDWORD event, UDWORD offset
psNewTrig->type = TR_PAUSE; psNewTrig->type = TR_PAUSE;
psNewTrig->event = (UWORD)event; psNewTrig->event = (UWORD)event;
psNewTrig->offset = (UWORD)offset; psNewTrig->offset = (UWORD)offset;
psNewTrig->deactivated = false;
// store the new trigger // store the new trigger
psNewTrig->psNext = psAddedTriggers; psNewTrig->psNext = psAddedTriggers;
psAddedTriggers = psNewTrig; psAddedTriggers = psNewTrig;
// tell the event system the trigger has been changed // mark the trigger for deletion
triggerChanged = true; psFiringTrigger->deactivated = true;
return true; return true;
} }
@ -1041,14 +1050,13 @@ void eventFireCallbackTrigger(TRIGGER_TYPE callback)
psPrev->psNext = psNext; psPrev->psNext = psNext;
} }
triggerChanged = false;
psFiringTrigger = psCurr; psFiringTrigger = psCurr;
if (!interpRunScript(psCurr->psContext, IRT_EVENT, psCurr->event, psCurr->offset)) // this could set triggerChanged if (!interpRunScript(psCurr->psContext, IRT_EVENT, psCurr->event, psCurr->offset)) // this could set psCurr->deactivated
{ {
ASSERT(false, "eventFireCallbackTrigger: event %s: code failed", ASSERT(false, "eventFireCallbackTrigger: event %s: code failed",
eventGetEventID(psCurr->psContext->psCode, psCurr->event)); eventGetEventID(psCurr->psContext->psCode, psCurr->event));
} }
if (triggerChanged) if (psCurr->deactivated)
{ {
// don't need to add the trigger again - just free it // don't need to add the trigger again - just free it
eventFreeTrigger(psCurr); eventFreeTrigger(psCurr);
@ -1056,8 +1064,8 @@ void eventFireCallbackTrigger(TRIGGER_TYPE callback)
else else
{ {
// make sure the trigger goes back into the system // make sure the trigger goes back into the system
psFiringTrigger->psNext = psAddedTriggers; psCurr->psNext = psAddedTriggers;
psAddedTriggers = psFiringTrigger; psAddedTriggers = psCurr;
} }
} }
else else
@ -1071,6 +1079,9 @@ void eventFireCallbackTrigger(TRIGGER_TYPE callback)
} }
} }
// Delete marked triggers now
eventPruneLists();
// Now add all the new triggers // Now add all the new triggers
for(psCurr = psAddedTriggers; psCurr; psCurr=psNext) for(psCurr = psAddedTriggers; psCurr; psCurr=psNext)
{ {
@ -1089,7 +1100,7 @@ static BOOL eventFireTrigger(ACTIVE_TRIGGER *psTrigger)
INTERP_VAL sResult; INTERP_VAL sResult;
fired = false; fired = false;
psFiringTrigger = psTrigger;
// If this is a code trigger see if it fires // If this is a code trigger see if it fires
if (psTrigger->type == TR_CODE) if (psTrigger->type == TR_CODE)
@ -1154,15 +1165,10 @@ void eventProcessTriggers(UDWORD currTime)
psCurr = psTrigList; psCurr = psTrigList;
psTrigList = psTrigList->psNext; psTrigList = psTrigList->psNext;
// Store the trigger so that I can tell if the event changes
// the trigger assigned to it
psFiringTrigger = psCurr;
triggerChanged = false;
// Run the trigger // Run the trigger
if (eventFireTrigger(psCurr)) // This might set triggerChanged if (eventFireTrigger(psCurr)) // This might mark the trigger for deletion
{ {
if (triggerChanged || psCurr->type == TR_WAIT) if (psCurr->deactivated || psCurr->type == TR_WAIT)
{ {
// remove the trigger // remove the trigger
eventFreeTrigger(psCurr); eventFreeTrigger(psCurr);
@ -1195,6 +1201,9 @@ void eventProcessTriggers(UDWORD currTime)
} }
} }
// Delete marked triggers now
eventPruneLists();
// Now add all the new triggers // Now add all the new triggers
for(psCurr = psAddedTriggers; psCurr; psCurr=psNext) for(psCurr = psAddedTriggers; psCurr; psCurr=psNext)
{ {
@ -1205,55 +1214,55 @@ void eventProcessTriggers(UDWORD currTime)
psAddedTriggers = NULL; psAddedTriggers = NULL;
} }
// remove all marked triggers
// remove a trigger from a list static void eventPruneList(ACTIVE_TRIGGER **ppsList)
static void eventRemoveTriggerFromList(ACTIVE_TRIGGER **ppsList,
SCRIPT_CONTEXT *psContext,
SDWORD event, SDWORD *pTrigger)
{ {
ACTIVE_TRIGGER *psCurr, *psPrev=NULL; ACTIVE_TRIGGER **ppsCurr = ppsList, *psTemp;
if (((*ppsList) != NULL) && while (*ppsCurr)
(*ppsList)->event == event &&
(*ppsList)->psContext == psContext)
{ {
if ((*ppsList)->type == TR_PAUSE) if ((*ppsCurr)->deactivated)
{ {
// pause trigger, don't remove it, psTemp = (*ppsCurr)->psNext;
// just note the type for when the pause finishes free(*ppsCurr);
(*ppsList)->trigger = (SWORD)*pTrigger; *ppsCurr = psTemp;
*pTrigger = -1;
} }
else else
{ {
psCurr = *ppsList; ppsCurr = &(*ppsCurr)->psNext;
*ppsList = (*ppsList)->psNext;
free(psCurr);
} }
} }
}
// Mark a trigger for removal from a list
static void eventMarkTriggerInList(ACTIVE_TRIGGER **ppsList,
SCRIPT_CONTEXT *psContext,
SDWORD event, SDWORD *pTrigger)
{
ACTIVE_TRIGGER **ppsCurr;
for (ppsCurr = ppsList;; ppsCurr = &(*ppsCurr)->psNext)
{
if (!(*ppsCurr))
{
return;
}
else if ((*ppsCurr)->event == event &&
(*ppsCurr)->psContext == psContext)
{
break;
}
}
if ((*ppsCurr)->type == TR_PAUSE)
{
// pause trigger, don't remove it,
// just note the type for when the pause finishes
(*ppsCurr)->trigger = (SWORD)*pTrigger;
*pTrigger = -1;
}
else else
{ {
for(psCurr=*ppsList; psCurr; psCurr=psCurr->psNext) (*ppsCurr)->deactivated = true;
{
if (psCurr->event == event &&
psCurr->psContext == psContext)
{
break;
}
psPrev = psCurr;
}
if (psCurr && psCurr->type == TR_PAUSE)
{
// pause trigger, don't remove it,
// just note the type for when the pause finishes
psCurr->trigger = (SWORD)*pTrigger;
*pTrigger = -1;
}
else if (psCurr)
{
psPrev->psNext = psCurr->psNext;
free(psCurr);
}
} }
} }
@ -1281,14 +1290,14 @@ BOOL eventSetTrigger(void)
psContext = psFiringTrigger->psContext; psContext = psFiringTrigger->psContext;
if (psFiringTrigger->event == event) if (psFiringTrigger->event == event)
{ {
triggerChanged = true; psFiringTrigger->deactivated = true;
} }
else else
{ {
// Remove any old trigger from the list // Mark the old trigger in the lists
eventRemoveTriggerFromList(&psTrigList, psContext, event, &trigger); eventMarkTriggerInList(&psTrigList, psContext, event, &trigger);
eventRemoveTriggerFromList(&psCallbackList, psContext, event, &trigger); eventMarkTriggerInList(&psCallbackList, psContext, event, &trigger);
eventRemoveTriggerFromList(&psAddedTriggers, psContext, event, &trigger); eventMarkTriggerInList(&psAddedTriggers, psContext, event, &trigger);
} }
// Create a new trigger if necessary // Create a new trigger if necessary

View File

@ -88,7 +88,7 @@ typedef struct _active_trigger
SWORD trigger; SWORD trigger;
UWORD event; UWORD event;
UWORD offset; UWORD offset;
BOOL deactivated; // Whether the trigger is marked for deletion
struct _active_trigger *psNext; struct _active_trigger *psNext;
} ACTIVE_TRIGGER; } ACTIVE_TRIGGER;