mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
The VM now aborts when a wrong self pointer is used with user variables to avoid random crashes
This commit is contained in:
parent
8aa09768f0
commit
b5b9baaa87
6 changed files with 37 additions and 3 deletions
|
@ -3373,6 +3373,19 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
if (~membervar->Flags & VARF_Native)
|
||||
{ // Check if this is a user-defined variable.
|
||||
// As of right now, FxClassMember is only ever used with FxSelf.
|
||||
// This very user variable was defined in stateowner so if
|
||||
// self (a0) != stateowner (a1) then the offset is most likely
|
||||
// going to end up being totally wrong even if the variable was
|
||||
// redefined in self which means we have to abort to avoid reading
|
||||
// or writing to a random address and possibly crash.
|
||||
build->Emit(OP_EQA_R, 1, 0, 1);
|
||||
build->Emit(OP_JMP, 1);
|
||||
build->Emit(OP_THROW, 2, X_BAD_SELF);
|
||||
}
|
||||
|
||||
ExpEmit obj = classx->Emit(build);
|
||||
assert(obj.RegType == REGT_POINTER);
|
||||
|
||||
|
|
|
@ -163,6 +163,7 @@ enum EVMAbortException
|
|||
X_TOO_MANY_TRIES,
|
||||
X_ARRAY_OUT_OF_BOUNDS,
|
||||
X_DIVISION_BY_ZERO,
|
||||
X_BAD_SELF,
|
||||
};
|
||||
|
||||
class VMFunction : public DObject
|
||||
|
|
|
@ -371,7 +371,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
|
|||
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
|
||||
if ((mode & MODE_BCTYPE) == MODE_BCTHROW)
|
||||
{
|
||||
mode = (code[i].a == 0) ? (MODE_BP | MODE_CUNUSED) : (MODE_BKP | MODE_CUNUSED);
|
||||
if (code[i].a == 0)
|
||||
{
|
||||
mode = (MODE_BP | MODE_CUNUSED);
|
||||
}
|
||||
else if (code[i].a == 1)
|
||||
{
|
||||
mode = (MODE_BKP | MODE_CUNUSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = (MODE_BCJOINT | MODE_BCIMMS);
|
||||
}
|
||||
}
|
||||
else if ((mode & MODE_BCTYPE) == MODE_BCCATCH)
|
||||
{
|
||||
|
|
|
@ -616,12 +616,16 @@ begin:
|
|||
ASSERTA(B);
|
||||
throw((VMException *)reg.a[B]);
|
||||
}
|
||||
else
|
||||
else if (a == 1)
|
||||
{
|
||||
ASSERTKA(B);
|
||||
assert(konstatag[B] == ATAG_OBJECT);
|
||||
throw((VMException *)konsta[B].o);
|
||||
}
|
||||
else
|
||||
{
|
||||
THROW(BC);
|
||||
}
|
||||
NEXTOP;
|
||||
OP(CATCH):
|
||||
// This instruction is handled by our own catch handler and should
|
||||
|
|
|
@ -440,6 +440,10 @@ int VMFrameStack::Call(VMFunction *func, VMValue *params, int numparams, VMRetur
|
|||
case X_DIVISION_BY_ZERO:
|
||||
Printf("division by zero.");
|
||||
break;
|
||||
|
||||
case X_BAD_SELF:
|
||||
Printf("invalid self pointer.");
|
||||
break;
|
||||
}
|
||||
Printf("\n");
|
||||
|
||||
|
|
|
@ -83,7 +83,8 @@ xx(RETI, reti, I8I16), // Copy immediate from BC to return value A, possibly re
|
|||
xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC
|
||||
xx(UNTRY, untry, I8), // Pop A entries off the exception stack
|
||||
xx(THROW, throw, THROW), // A == 0: Throw exception object pB
|
||||
// A != 0: Throw exception object pkB
|
||||
// A == 1: Throw exception object pkB
|
||||
// A >= 2: Throw VM exception of type BC
|
||||
xx(CATCH, catch, CATCH), // A == 0: continue search on next try
|
||||
// A == 1: continue execution at instruction immediately following CATCH (catches any exception)
|
||||
// A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
|
||||
|
|
Loading…
Reference in a new issue