* Fixed a crash uncovered with r14501, caused by outdated local variables when a script is about to suspend or terminate (bugreport:4577).

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@14511 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
ai4rei 2010-11-28 02:02:30 +00:00
parent 2c88023b3d
commit a5326bd2b6
3 changed files with 82 additions and 58 deletions

View File

@ -1,6 +1,7 @@
Date Added Date Added
2010/11/27 2010/11/27
* Fixed a crash uncovered with r14501, caused by outdated local variables when a script is about to suspend or terminate (bugreport:4577). [Ai4rei]
* Fixed a crash when using food status bonuses with cash food status bonuses (bugreport:4582, since r14437). [Ai4rei] * Fixed a crash when using food status bonuses with cash food status bonuses (bugreport:4582, since r14437). [Ai4rei]
2010/11/26 2010/11/26
* Fixed description of bCriticalAddRace having 'race' and 'crit' parameters interchanged (bugreport:4383, since r1116 and r1382, related r12804). [Ai4rei] * Fixed description of bCriticalAddRace having 'race' and 'crit' parameters interchanged (bugreport:4383, since r1116 and r1382, related r12804). [Ai4rei]

View File

@ -2694,6 +2694,10 @@ struct script_state* script_alloc_state(struct script_code* script, int pos, int
/// @param st Script state /// @param st Script state
void script_free_state(struct script_state* st) void script_free_state(struct script_state* st)
{ {
if(st->bk_st)
{// backup was not restored
ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
}
if( st->sleep.timer != INVALID_TIMER ) if( st->sleep.timer != INVALID_TIMER )
delete_timer(st->sleep.timer, run_script_timer); delete_timer(st->sleep.timer, run_script_timer);
script_free_vars(st->stack->var_function); script_free_vars(st->stack->var_function);
@ -3138,6 +3142,63 @@ int run_script_timer(int tid, unsigned int tick, int id, intptr data)
return 0; return 0;
} }
/// Detaches script state from possibly attached character and restores it's previous script if any.
///
/// @param st Script state to detach.
/// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
static void script_detach_state(struct script_state* st, bool dequeue_event)
{
struct map_session_data* sd;
if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
{
sd->st = st->bk_st;
sd->npc_id = st->bk_npcid;
if(st->bk_st)
{
//Remove tag for removal.
st->bk_st = NULL;
st->bk_npcid = 0;
}
else if(dequeue_event)
{
npc_event_dequeue(sd);
}
}
else if(st->bk_st)
{// rid was set to 0, before detaching the script state
ShowError("script_detach_state: Found previous script state without attached player (rid=%d, oid=%d, state=%d, bk_npcid=%d)\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
script_reportsrc(st->bk_st);
script_free_state(st->bk_st);
st->bk_st = NULL;
}
}
/// Attaches script state to possibly attached character and backups it's previous script, if any.
///
/// @param st Script state to attach.
static void script_attach_state(struct script_state* st)
{
struct map_session_data* sd;
if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
{
if(st!=sd->st)
{
if(st->bk_st)
{// there is already a backup
ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
}
st->bk_st = sd->st;
st->bk_npcid = sd->npc_id;
}
sd->st = st;
sd->npc_id = st->oid;
}
}
/*========================================== /*==========================================
* *
*------------------------------------------*/ *------------------------------------------*/
@ -3146,22 +3207,10 @@ void run_script_main(struct script_state *st)
int cmdcount=script_config.check_cmdcount; int cmdcount=script_config.check_cmdcount;
int gotocount=script_config.check_gotocount; int gotocount=script_config.check_gotocount;
TBL_PC *sd; TBL_PC *sd;
//For backing up purposes
struct script_state *bk_st = NULL;
int bk_npcid = 0;
struct script_stack *stack=st->stack; struct script_stack *stack=st->stack;
struct npc_data *nd; struct npc_data *nd;
sd = map_id2sd(st->rid); script_attach_state(st);
if(sd){
if(sd->st != st){
bk_st = sd->st;
bk_npcid = sd->npc_id;
}
sd->st = st;
sd->npc_id = st->oid;
}
nd = map_id2nd(st->oid); nd = map_id2nd(st->oid);
if( nd && map[nd->bl.m].instance_id > 0 ) if( nd && map[nd->bl.m].instance_id > 0 )
@ -3260,43 +3309,37 @@ void run_script_main(struct script_state *st)
if(st->sleep.tick > 0) { if(st->sleep.tick > 0) {
//Restore previous script //Restore previous script
if (sd) { script_detach_state(st, false);
sd->st = bk_st;
sd->npc_id = bk_npcid;
bk_st = NULL; //Remove tag for removal.
}
//Delay execution //Delay execution
sd = map_id2sd(st->rid); // Refresh sd since script might have attached someone while running. [Inkfish] sd = map_id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish]
st->sleep.charid = sd?sd->status.char_id:0; st->sleep.charid = sd?sd->status.char_id:0;
st->sleep.timer = add_timer(gettick()+st->sleep.tick, st->sleep.timer = add_timer(gettick()+st->sleep.tick,
run_script_timer, st->sleep.charid, (intptr)st); run_script_timer, st->sleep.charid, (intptr)st);
linkdb_insert(&sleep_db, (void*)st->oid, st); linkdb_insert(&sleep_db, (void*)st->oid, st);
} }
else if(st->state != END && sd){ else if(st->state != END && st->rid){
//Resume later (st is already attached to player). //Resume later (st is already attached to player).
if(bk_st) { if(st->bk_st) {
ShowWarning("Unable to restore stack! Double continuation!\n"); ShowWarning("Unable to restore stack! Double continuation!\n");
//Report BOTH scripts to see if that can help somehow. //Report BOTH scripts to see if that can help somehow.
ShowDebug("Previous script (lost):\n"); ShowDebug("Previous script (lost):\n");
script_reportsrc(bk_st); script_reportsrc(st->bk_st);
ShowDebug("Current script:\n"); ShowDebug("Current script:\n");
script_reportsrc(st); script_reportsrc(st);
script_free_state(st->bk_st);
st->bk_st = NULL;
} }
} else { } else {
//Dispose of script. //Dispose of script.
if (sd) if ((sd = map_id2sd(st->rid))!=NULL)
{ //Restore previous stack and save char. { //Restore previous stack and save char.
if(sd->state.using_fake_npc){ if(sd->state.using_fake_npc){
clif_clearunit_single(sd->npc_id, 0, sd->fd); clif_clearunit_single(sd->npc_id, 0, sd->fd);
sd->state.using_fake_npc = 0; sd->state.using_fake_npc = 0;
} }
//Restore previous script if any. //Restore previous script if any.
sd->st = bk_st; script_detach_state(st, true);
sd->npc_id = bk_npcid;
if (!bk_st)
npc_event_dequeue(sd);
else
bk_st = NULL; //Remove tag for removal.
if (sd->state.reg_dirty&2) if (sd->state.reg_dirty&2)
intif_saveregistry(sd,2); intif_saveregistry(sd,2);
if (sd->state.reg_dirty&1) if (sd->state.reg_dirty&1)
@ -3305,13 +3348,6 @@ void run_script_main(struct script_state *st)
script_free_state(st); script_free_state(st);
st = NULL; st = NULL;
} }
if (bk_st)
{ //Remove previous script
script_free_state(bk_st);
bk_st = NULL;
}
} }
int script_config_read(char *cfgName) int script_config_read(char *cfgName)
@ -9087,23 +9123,14 @@ BUILDIN_FUNC(warpwaitingpc)
// ... // ...
// //
/// Detaches a character from a script.
///
/// @param st Script state to detach the character from.
static void script_detach_rid(struct script_state* st) static void script_detach_rid(struct script_state* st)
{ {
struct map_session_data* sd;
if(st->rid) if(st->rid)
{ {
if((sd = script_rid2sd(st))!=NULL) script_detach_state(st, false);
{
if(sd->npc_id!=st->oid)
{
ShowDebug("script_detach_rid: sd->npc_id (%d) != st->oid (%d), please report this!\n", sd->npc_id, st->oid);
script_reportsrc(st);
}
sd->npc_id = 0;
sd->st = NULL;
}
st->rid = 0; st->rid = 0;
} }
} }
@ -9119,9 +9146,8 @@ BUILDIN_FUNC(attachrid)
if ((sd = map_id2sd(rid))!=NULL) { if ((sd = map_id2sd(rid))!=NULL) {
script_detach_rid(st); script_detach_rid(st);
sd->st = st;
sd->npc_id = st->oid;
st->rid = rid; st->rid = rid;
script_attach_state(st);
script_pushint(st,1); script_pushint(st,1);
} else } else
script_pushint(st,0); script_pushint(st,0);
@ -13238,17 +13264,11 @@ BUILDIN_FUNC(unitskillusepos)
BUILDIN_FUNC(sleep) BUILDIN_FUNC(sleep)
{ {
int ticks; int ticks;
TBL_PC* sd;
ticks = script_getnum(st,2); ticks = script_getnum(st,2);
sd = map_id2sd(st->rid);
// detach the player // detach the player
if( sd && sd->npc_id == st->oid ) script_detach_rid(st);
{
sd->npc_id = 0;
}
st->rid = 0;
if( ticks <= 0 ) if( ticks <= 0 )
{// do nothing {// do nothing

View File

@ -121,6 +121,9 @@ struct script_state {
int tick,timer,charid; int tick,timer,charid;
} sleep; } sleep;
int instance_id; int instance_id;
//For backing up purposes
struct script_state *bk_st;
int bk_npcid;
}; };
struct script_reg { struct script_reg {