The VM now aborts when a wrong self pointer is used with user variables to avoid random crashes

This commit is contained in:
Leonard2 2016-09-14 13:56:58 +02:00 committed by Christoph Oelckers
parent 8aa09768f0
commit b5b9baaa87
6 changed files with 37 additions and 3 deletions

View file

@ -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);

View file

@ -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

View file

@ -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)
{

View file

@ -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

View file

@ -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");

View file

@ -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