Skip to content

Commit e7a322f

Browse files
committed
Detect state cycles in P_SetMobjState()
Fixes crash in MAP10 of Dominus Diabolicus 2. Thanks bofu! https://www.doomworld.com/forum/post/2920133
1 parent 9bf0f02 commit e7a322f

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

src/p_mobj.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,26 @@
5858
//
5959
bool P_SetMobjState(mobj_t *mobj, statenum_t state)
6060
{
61+
// killough 4/9/98: remember states seen, to detect cycles:
62+
63+
// fast transition table
64+
statenum_t *seenstate = seenstate_tab; // pointer to table
65+
static int recursion; // detects recursion
66+
statenum_t i = state; // initial state
67+
boolean ret = true; // return value
68+
statenum_t *tempstate = NULL; // for use with recursion
69+
70+
if (recursion++) // if recursion detected, allocate state table
71+
seenstate = tempstate = Z_Calloc(numstates, sizeof(statenum_t), PU_STATIC, NULL);
72+
6173
do
6274
{
6375
if (state == S_NULL)
6476
{
6577
mobj->state = (state_t *)S_NULL;
6678
P_RemoveMobj(mobj);
67-
68-
return false;
79+
ret = false;
80+
break; // killough 4/9/98
6981
}
7082
else
7183
{
@@ -81,11 +93,19 @@ bool P_SetMobjState(mobj_t *mobj, statenum_t state)
8193
if (st->action)
8294
st->action(mobj, NULL, NULL);
8395

96+
seenstate[state] = 1 + st->nextstate; // killough 4/9/98
8497
state = st->nextstate;
8598
}
86-
} while (!mobj->tics);
99+
} while (!mobj->tics && !seenstate[state]); // killough 4/9/98
87100

88-
return true;
101+
if (!--recursion)
102+
for (; (state = seenstate[i]); i = state - 1)
103+
seenstate[i] = 0; // killough 4/9/98: erase memory of states
104+
105+
if (tempstate)
106+
Z_Free(tempstate);
107+
108+
return ret;
89109
}
90110

91111
//

src/states.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1509,14 +1509,18 @@ state_t original_states[] =
15091509
// DSDHacked
15101510
state_t *states;
15111511
int numstates;
1512-
byte *defined_codeptr_args;
1512+
byte *defined_codeptr_args = NULL;
1513+
statenum_t *seenstate_tab = NULL;
15131514
actionf_t *deh_codeptr;
15141515

15151516
void InitStates(void)
15161517
{
15171518
numstates = NUMSTATES;
15181519
states = original_states;
15191520

1521+
array_grow(seenstate_tab, numstates);
1522+
memset(seenstate_tab, 0, numstates * sizeof(*seenstate_tab));
1523+
15201524
array_grow(deh_codeptr, numstates);
15211525

15221526
for (int i = 0; i < numstates; i++)

src/states.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,7 @@ extern state_t *states;
11791179
extern int numstates;
11801180
extern actionf_t *deh_codeptr;
11811181
extern byte *defined_codeptr_args;
1182+
extern statenum_t *seenstate_tab;
11821183

11831184
void InitStates(void);
11841185
void FreeStates(void);

0 commit comments

Comments
 (0)