mirror of https://github.com/ZDoom/gzdoom-gles.git
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
|
@ -3373,6 +3373,19 @@ FxExpression *FxClassMember::Resolve(FCompileContext &ctx)
|
||||||
|
|
||||||
ExpEmit FxClassMember::Emit(VMFunctionBuilder *build)
|
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);
|
ExpEmit obj = classx->Emit(build);
|
||||||
assert(obj.RegType == REGT_POINTER);
|
assert(obj.RegType == REGT_POINTER);
|
||||||
|
|
||||||
|
|
|
@ -163,6 +163,7 @@ enum EVMAbortException
|
||||||
X_TOO_MANY_TRIES,
|
X_TOO_MANY_TRIES,
|
||||||
X_ARRAY_OUT_OF_BOUNDS,
|
X_ARRAY_OUT_OF_BOUNDS,
|
||||||
X_DIVISION_BY_ZERO,
|
X_DIVISION_BY_ZERO,
|
||||||
|
X_BAD_SELF,
|
||||||
};
|
};
|
||||||
|
|
||||||
class VMFunction : public DObject
|
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);
|
col = print_reg(out, 0, a, (mode & MODE_ATYPE) >> MODE_ASHIFT, 24, func);
|
||||||
if ((mode & MODE_BCTYPE) == MODE_BCTHROW)
|
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)
|
else if ((mode & MODE_BCTYPE) == MODE_BCCATCH)
|
||||||
{
|
{
|
||||||
|
|
|
@ -616,12 +616,16 @@ begin:
|
||||||
ASSERTA(B);
|
ASSERTA(B);
|
||||||
throw((VMException *)reg.a[B]);
|
throw((VMException *)reg.a[B]);
|
||||||
}
|
}
|
||||||
else
|
else if (a == 1)
|
||||||
{
|
{
|
||||||
ASSERTKA(B);
|
ASSERTKA(B);
|
||||||
assert(konstatag[B] == ATAG_OBJECT);
|
assert(konstatag[B] == ATAG_OBJECT);
|
||||||
throw((VMException *)konsta[B].o);
|
throw((VMException *)konsta[B].o);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
THROW(BC);
|
||||||
|
}
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
OP(CATCH):
|
OP(CATCH):
|
||||||
// This instruction is handled by our own catch handler and should
|
// 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:
|
case X_DIVISION_BY_ZERO:
|
||||||
Printf("division by zero.");
|
Printf("division by zero.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case X_BAD_SELF:
|
||||||
|
Printf("invalid self pointer.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Printf("\n");
|
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(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(UNTRY, untry, I8), // Pop A entries off the exception stack
|
||||||
xx(THROW, throw, THROW), // A == 0: Throw exception object pB
|
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
|
xx(CATCH, catch, CATCH), // A == 0: continue search on next try
|
||||||
// A == 1: continue execution at instruction immediately following CATCH (catches any exception)
|
// 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
|
// A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
|
||||||
|
|
Loading…
Reference in New Issue