- added null pointer validation to any relevant exported function. In most cases null pointers were already being treated as 'do nothing', but there's several places where this can make the code silently fail so in these cases a VM exception will be raised, once the VM's exception handling has been repaired to provide useful diagnostics. (Right now all it does is catch the exception, print a useless message and return to the caller as if nothing has happened.)

This commit is contained in:
Christoph Oelckers 2016-12-02 12:06:49 +01:00
parent 82c2670617
commit f9441cd9d9
17 changed files with 160 additions and 136 deletions

View file

@ -9697,7 +9697,7 @@ int BuiltinClassCast(VMValue *param, TArray<VMValue> &defaultparam, int numparam
PARAM_PROLOGUE;
PARAM_CLASS(from, DObject);
PARAM_CLASS(to, DObject);
ACTION_RETURN_OBJECT(from->IsDescendantOf(to) ? from : nullptr);
ACTION_RETURN_OBJECT(from && to && from->IsDescendantOf(to) ? from : nullptr);
}
ExpEmit FxClassPtrCast::Emit(VMFunctionBuilder *build)

View file

@ -951,6 +951,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
// Use these to collect the parameters in a native function.
// variable name <x> at position <p>
void NullParam(const char *varname);
#define PARAM_NULLCHECK(ptr, var) (ptr == nullptr? NullParam(#var), ptr : ptr)
// For required parameters.
#define PARAM_INT_AT(p,x) assert((p) < numparam); assert(param[p].Type == REGT_INT); int x = param[p].i;
@ -966,6 +969,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)param[p].a;
#define PARAM_OBJECT_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)param[p].a; assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)param[p].a; assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
#define PARAM_POINTER_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x);
#define PARAM_OBJECT_NOT_NULL_AT(p,x,type) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); type *x = (type *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsKindOf(RUNTIME_CLASS(type)));
#define PARAM_CLASS_NOT_NULL_AT(p,x,base) assert((p) < numparam); assert(param[p].Type == REGT_POINTER && (param[p].atag == ATAG_OBJECT || param[p].a == NULL)); base::MetaClass *x = (base::MetaClass *)PARAM_NULLCHECK(param[p].a, #x); assert(x == NULL || x->IsDescendantOf(RUNTIME_CLASS(base)));
#define PARAM_EXISTS(p) ((p) < numparam)
#define ASSERTINT(p) assert((p).Type == REGT_INT)
@ -988,6 +994,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTPOINTER(param[p]); x = (t*)param[p].a; } else { ASSERTPOINTER(defaultparam[p]); x = (t*)defaultparam[p].a; }
#define PARAM_OBJECT_DEF_AT(p,x,t) t *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t*)defaultparam[p].a; }
#define PARAM_CLASS_DEF_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)param[p].a; } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)defaultparam[p].a; }
#define PARAM_CLASS_DEF_NOT_NULL_AT(p,x,t) t::MetaClass *x; if (PARAM_EXISTS(p)) { ASSERTOBJECT(param[p]); x = (t::MetaClass*)PARAM_NULLCHECK(param[p].a, #x); } else { ASSERTOBJECT(defaultparam[p]); x = (t::MetaClass*)PARAM_NULLCHECK(defaultparam[p].a, #x); }
// The above, but with an automatically increasing position index.
#define PARAM_PROLOGUE int paramnum = -1;
@ -1005,6 +1012,9 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER(x,type) ++paramnum; PARAM_POINTER_AT(paramnum,x,type)
#define PARAM_OBJECT(x,type) ++paramnum; PARAM_OBJECT_AT(paramnum,x,type)
#define PARAM_CLASS(x,base) ++paramnum; PARAM_CLASS_AT(paramnum,x,base)
#define PARAM_POINTER_NOT_NULL(x,type) ++paramnum; PARAM_POINTER_NOT_NULL_AT(paramnum,x,type)
#define PARAM_OBJECT_NOT_NULL(x,type) ++paramnum; PARAM_OBJECT_NOT_NULL_AT(paramnum,x,type)
#define PARAM_CLASS_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_NOT_NULL_AT(paramnum,x,base)
#define PARAM_INT_DEF(x) ++paramnum; PARAM_INT_DEF_AT(paramnum,x)
#define PARAM_BOOL_DEF(x) ++paramnum; PARAM_BOOL_DEF_AT(paramnum,x)
@ -1019,6 +1029,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction
#define PARAM_POINTER_DEF(x,type) ++paramnum; PARAM_POINTER_DEF_AT(paramnum,x,type)
#define PARAM_OBJECT_DEF(x,type) ++paramnum; PARAM_OBJECT_DEF_AT(paramnum,x,type)
#define PARAM_CLASS_DEF(x,base) ++paramnum; PARAM_CLASS_DEF_AT(paramnum,x,base)
#define PARAM_CLASS_DEF_NOT_NULL(x,base) ++paramnum; PARAM_CLASS_DEF_NOT_NULL_AT(paramnum,x,base)
typedef int(*actionf_p)(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/

View file

@ -228,3 +228,7 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam)
}
}
}
void NullParam(const char *varname)
{
}