diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index ce603f261..695b12799 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -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); diff --git a/src/zscript/vm.h b/src/zscript/vm.h index 0d45ad90a..a000e9533 100644 --- a/src/zscript/vm.h +++ b/src/zscript/vm.h @@ -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 diff --git a/src/zscript/vmdisasm.cpp b/src/zscript/vmdisasm.cpp index 35eb6085d..4e6f33ec7 100644 --- a/src/zscript/vmdisasm.cpp +++ b/src/zscript/vmdisasm.cpp @@ -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) { diff --git a/src/zscript/vmexec.h b/src/zscript/vmexec.h index 42a374030..adf2986c5 100644 --- a/src/zscript/vmexec.h +++ b/src/zscript/vmexec.h @@ -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 diff --git a/src/zscript/vmframe.cpp b/src/zscript/vmframe.cpp index 29da0c5b9..50c7d78d9 100644 --- a/src/zscript/vmframe.cpp +++ b/src/zscript/vmframe.cpp @@ -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"); diff --git a/src/zscript/vmops.h b/src/zscript/vmops.h index decb0b93d..39d224f5c 100644 --- a/src/zscript/vmops.h +++ b/src/zscript/vmops.h @@ -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 == ) then pc++ ; next instruction must JMP to another CATCH