From f9441cd9d98684d2db56ab8082f3ce9de02c541e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Dec 2016 12:06:49 +0100 Subject: [PATCH] - 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.) --- src/g_inventory/a_pickups.cpp | 10 +- src/g_shared/a_morph.cpp | 2 +- src/g_shared/a_specialspot.cpp | 3 +- src/p_actionfunctions.cpp | 2 +- src/p_ceiling.cpp | 2 +- src/p_enemy.cpp | 16 +-- src/p_floor.cpp | 2 +- src/p_interaction.cpp | 2 +- src/p_map.cpp | 3 +- src/p_maputl.cpp | 2 +- src/p_mobj.cpp | 162 ++++++++++++----------- src/p_pspr.cpp | 58 ++++---- src/p_sight.cpp | 2 +- src/p_states.cpp | 13 +- src/scripting/codegeneration/codegen.cpp | 2 +- src/scripting/vm/vm.h | 11 ++ src/scripting/vm/vmexec.cpp | 4 + 17 files changed, 160 insertions(+), 136 deletions(-) diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 51072023b..bdd1b6dc6 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -261,7 +261,7 @@ bool AInventory::SpecialDropAction (AActor *dropper) DEFINE_ACTION_FUNCTION(AInventory, SpecialDropAction) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_OBJECT(dropper, AActor); + PARAM_OBJECT_NOT_NULL(dropper, AActor); ACTION_RETURN_BOOL(self->SpecialDropAction(dropper)); } @@ -429,7 +429,7 @@ bool AInventory::HandlePickup (AInventory *item) DEFINE_ACTION_FUNCTION(AInventory, HandlePickup) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_BOOL(self->HandlePickup(item)); } @@ -1416,7 +1416,7 @@ bool AInventory::TryPickup (AActor *&toucher) DEFINE_ACTION_FUNCTION(AInventory, TryPickup) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_POINTER(toucher, AActor*); + PARAM_POINTER_NOT_NULL(toucher, AActor*); ACTION_RETURN_BOOL(self->TryPickup(*toucher)); } @@ -1434,7 +1434,7 @@ bool AInventory::TryPickupRestricted (AActor *&toucher) DEFINE_ACTION_FUNCTION(AInventory, TryPickupRestricted) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_POINTER(toucher, AActor*); + PARAM_POINTER_NOT_NULL(toucher, AActor*); ACTION_RETURN_BOOL(self->TryPickupRestricted(*toucher)); } @@ -1613,7 +1613,7 @@ void AInventory::AttachToOwner (AActor *other) DEFINE_ACTION_FUNCTION(AInventory, AttachToOwner) { PARAM_SELF_PROLOGUE(AInventory); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); self->AttachToOwner(other); return 0; } diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 03f76c0c0..136c096a3 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -363,7 +363,7 @@ bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, DEFINE_ACTION_FUNCTION(_PlayerInfo, UndoPlayerMorph) { PARAM_SELF_STRUCT_PROLOGUE(player_t); - PARAM_POINTER(player, player_t); + PARAM_POINTER_NOT_NULL(player, player_t); PARAM_INT_DEF(unmorphflag); PARAM_BOOL_DEF(force); ACTION_RETURN_BOOL(P_UndoPlayerMorph(self, player, unmorphflag, force)); diff --git a/src/g_shared/a_specialspot.cpp b/src/g_shared/a_specialspot.cpp index 026185d07..b5debf2df 100644 --- a/src/g_shared/a_specialspot.cpp +++ b/src/g_shared/a_specialspot.cpp @@ -265,6 +265,7 @@ DEFINE_ACTION_FUNCTION(DSpotState, GetSpotState) FSpotList *DSpotState::FindSpotList(PClassActor *type) { + if (type == nullptr) return nullptr; for(unsigned i = 0; i < SpotLists.Size(); i++) { if (SpotLists[i].Type == type) return &SpotLists[i]; @@ -404,7 +405,7 @@ void ASpecialSpot::Destroy() DEFINE_ACTION_FUNCTION(AActor, A_SpawnSingleItem) { PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS (cls, AActor); + PARAM_CLASS_NOT_NULL(cls, AActor); PARAM_INT_DEF (fail_sp) PARAM_INT_DEF (fail_co) PARAM_INT_DEF (fail_dm) diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 477ed37f2..115bc1f54 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -247,7 +247,7 @@ DEFINE_ACTION_FUNCTION(AActor, CheckClass) PARAM_BOOL_DEF (match_superclass); self = COPY_AAPTR(self, pick_pointer); - if (self == NULL) + if (self == nullptr || checktype == nullptr) { ret->SetInt(false); } diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 932b4c649..4da81db46 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -461,7 +461,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t DEFINE_ACTION_FUNCTION(DCeiling, CreateCeiling) { PARAM_PROLOGUE; - PARAM_POINTER(sec, sector_t); + PARAM_POINTER_NOT_NULL(sec, sector_t); PARAM_INT(type); PARAM_POINTER(ln, line_t); PARAM_FLOAT(speed); diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 751f92a30..beaa1548f 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1307,6 +1307,11 @@ bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams double mindist; DAngle fov; + if (other == nullptr) + { + return false; + } + if (params != NULL) { maxdist = params->maxDist; @@ -3095,7 +3100,7 @@ void A_FaceTarget(AActor *self) DEFINE_ACTION_FUNCTION(AActor, A_Face) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(faceto, AActor) + PARAM_OBJECT_NOT_NULL(faceto, AActor) PARAM_ANGLE_DEF(max_turn) PARAM_ANGLE_DEF(max_pitch) PARAM_ANGLE_DEF(ang_offset) @@ -3323,15 +3328,6 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c return NULL; } -DEFINE_ACTION_FUNCTION(AActor, DoDropItem) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_CLASS(cls, AActor); - PARAM_INT(amt); - PARAM_INT(chance); - ACTION_RETURN_OBJECT(P_DropItem(self, cls, amt, chance)); -} - //============================================================================ // // P_TossItem diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 8fd5ad038..4b1f243d5 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -495,7 +495,7 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line, DEFINE_ACTION_FUNCTION(DFloor, CreateFloor) { PARAM_PROLOGUE; - PARAM_POINTER(sec, sector_t); + PARAM_POINTER_NOT_NULL(sec, sector_t); PARAM_INT(floortype); PARAM_POINTER(ln, line_t); PARAM_FLOAT(speed); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index e6729096c..9aa178e64 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1639,7 +1639,7 @@ void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage DEFINE_ACTION_FUNCTION(AActor, PoisonMobj) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(inflictor, AActor); + PARAM_OBJECT_NOT_NULL(inflictor, AActor); PARAM_OBJECT(source, AActor); PARAM_INT(damage); PARAM_INT(duration); diff --git a/src/p_map.cpp b/src/p_map.cpp index 11036d171..f25c33612 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -4513,6 +4513,7 @@ DEFINE_ACTION_FUNCTION(AActor, LineAttack) PARAM_POINTER_DEF(victim, FTranslatedLineTarget); int acdmg; + if (puffType == nullptr) puffType = PClass::FindActor("BulletPuff"); // P_LineAttack does not work without a puff to take info from. auto puff = P_LineAttack(self, angle, distance, pitch, damage, damageType, puffType, flags, victim, &acdmg); if (numret > 0) ret[0].SetPointer(puff, ATAG_OBJECT); if (numret > 1) ret[1].SetInt(acdmg), numret = 2; @@ -4716,7 +4717,7 @@ DEFINE_ACTION_FUNCTION(_FTranslatedLineTarget, TraceBleed) { PARAM_SELF_STRUCT_PROLOGUE(FTranslatedLineTarget); PARAM_INT(damage); - PARAM_OBJECT(missile, AActor); + PARAM_OBJECT_NOT_NULL(missile, AActor); P_TraceBleed(damage, self, missile); return 0; diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp index aa29a1c5e..31b412598 100644 --- a/src/p_maputl.cpp +++ b/src/p_maputl.cpp @@ -1193,7 +1193,7 @@ IMPLEMENT_CLASS(DBlockThingsIterator, false, false); DEFINE_ACTION_FUNCTION(DBlockThingsIterator, Create) { PARAM_PROLOGUE; - PARAM_OBJECT(origin, AActor); + PARAM_OBJECT_NOT_NULL(origin, AActor); PARAM_FLOAT_DEF(radius); PARAM_BOOL_DEF(ignore); ACTION_RETURN_OBJECT(new DBlockThingsIterator(origin, radius, ignore)); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 26e362d8f..88653fca9 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -751,7 +751,7 @@ void AActor::AddInventory (AInventory *item) DEFINE_ACTION_FUNCTION(AActor, AddInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); self->AddInventory(item); return 0; } @@ -819,7 +819,7 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) DEFINE_ACTION_FUNCTION(AActor, Inventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_BOOL(self->UseInventory(item)); } @@ -854,7 +854,7 @@ void AActor::RemoveInventory(AInventory *item) DEFINE_ACTION_FUNCTION(AActor, RemoveInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); self->RemoveInventory(item); return 0; } @@ -1009,7 +1009,7 @@ bool AActor::UseInventory (AInventory *item) DEFINE_ACTION_FUNCTION(AActor, UseInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_BOOL(self->UseInventory(item)); } @@ -1042,7 +1042,7 @@ AInventory *AActor::DropInventory (AInventory *item) DEFINE_ACTION_FUNCTION(AActor, DropInventory) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(item, AInventory); + PARAM_OBJECT_NOT_NULL(item, AInventory); ACTION_RETURN_OBJECT(self->DropInventory(item)); } @@ -1263,7 +1263,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget, bool resetHealt DEFINE_ACTION_FUNCTION(AActor, CopyFriendliness) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); PARAM_BOOL_DEF(changetarget); PARAM_BOOL_DEF(resethealth); self->CopyFriendliness(other, changetarget, resethealth); @@ -1486,7 +1486,7 @@ void AActor::Touch (AActor *toucher) DEFINE_ACTION_FUNCTION(AActor, Touch) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(toucher, AActor); + PARAM_OBJECT_NOT_NULL(toucher, AActor); self->Touch(toucher); return 0; } @@ -2000,7 +2000,7 @@ bool AActor::CanSeek(AActor *target) const DEFINE_ACTION_FUNCTION(AActor, CanSeek) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); ACTION_RETURN_BOOL(self->CanSeek(target)); } @@ -4669,7 +4669,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a DEFINE_ACTION_FUNCTION(AActor, Spawn) { PARAM_PROLOGUE; - PARAM_CLASS(type, AActor); + PARAM_CLASS_NOT_NULL(type, AActor); PARAM_FLOAT_DEF(x); PARAM_FLOAT_DEF(y); PARAM_FLOAT_DEF(z); @@ -5656,6 +5656,8 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1 AActor *puff; DVector3 pos = pos1; + if (pufftype == nullptr) return nullptr; + if (!(flags & PF_NORANDOMZ)) pos.Z += pr_spawnpuff.Random2() / 64.; puff = Spawn(pufftype, pos, ALLOW_REPLACE); if (puff == NULL) return NULL; @@ -6163,7 +6165,7 @@ foundone: DEFINE_ACTION_FUNCTION(AActor, HitWater) { PARAM_SELF_PROLOGUE(AActor); - PARAM_POINTER(sec, sector_t); + PARAM_POINTER_NOT_NULL(sec, sector_t); PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_FLOAT(z); @@ -6383,7 +6385,7 @@ void P_PlaySpawnSound(AActor *missile, AActor *spawner) DEFINE_ACTION_FUNCTION(AActor, PlaySpawnSound) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(missile, AActor); + PARAM_OBJECT_NOT_NULL(missile, AActor); P_PlaySpawnSound(missile, self); return 0; } @@ -6415,47 +6417,11 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed) // //--------------------------------------------------------------------------- -AActor *P_SpawnMissile (AActor *source, AActor *dest, PClassActor *type, AActor *owner) -{ - if (source == NULL) - { - return NULL; - } - return P_SpawnMissileXYZ (source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); -} - -DEFINE_ACTION_FUNCTION(AActor, SpawnMissile) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(dest, AActor); - PARAM_CLASS(type, AActor); - PARAM_OBJECT_DEF(owner, AActor); - ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner)); -} - -AActor *P_SpawnMissileZ (AActor *source, double z, AActor *dest, PClassActor *type) -{ - if (source == NULL) - { - return NULL; - } - return P_SpawnMissileXYZ (source->PosAtZ(z), source, dest, type); -} - -DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_FLOAT(z); - PARAM_OBJECT(dest, AActor); - PARAM_CLASS(type, AActor); - ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type)); -} - AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassActor *type, bool checkspawn, AActor *owner) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } if (dest == NULL) @@ -6530,19 +6496,56 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileXYZ) PARAM_FLOAT(x); PARAM_FLOAT(y); PARAM_FLOAT(z); - PARAM_OBJECT(dest, AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); PARAM_CLASS(type, AActor); PARAM_BOOL_DEF(check); PARAM_OBJECT_DEF(owner, AActor); ACTION_RETURN_OBJECT(P_SpawnMissileXYZ(DVector3(x,y,z), self, dest, type, check, owner)); } +AActor *P_SpawnMissile(AActor *source, AActor *dest, PClassActor *type, AActor *owner) +{ + if (source == nullptr) + { + return nullptr; + } + return P_SpawnMissileXYZ(source->PosPlusZ(32 + source->GetBobOffset()), source, dest, type, true, owner); +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnMissile) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + PARAM_OBJECT_DEF(owner, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissile(self, dest, type, owner)); +} + +AActor *P_SpawnMissileZ(AActor *source, double z, AActor *dest, PClassActor *type) +{ + if (source == nullptr) + { + return nullptr; + } + return P_SpawnMissileXYZ(source->PosAtZ(z), source, dest, type); +} + +DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZ) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_FLOAT(z); + PARAM_OBJECT_NOT_NULL(dest, AActor); + PARAM_CLASS(type, AActor); + ACTION_RETURN_OBJECT(P_SpawnMissileZ(self, z, dest, type)); +} + + AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassActor *type) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } AActor *th = Spawn (type, source->PosPlusZ(32.), ALLOW_REPLACE); @@ -6568,7 +6571,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(dest, AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); PARAM_CLASS(type, AActor); PARAM_OBJECT_DEF(owner, AActor); ACTION_RETURN_OBJECT(P_OldSpawnMissile(self, owner, dest, type)); @@ -6586,7 +6589,7 @@ DEFINE_ACTION_FUNCTION(AActor, OldSpawnMissile) AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, double vz) { - if (source == NULL) + if (source == nullptr || type == nullptr) { return NULL; } @@ -6595,14 +6598,18 @@ AActor *P_SpawnMissileAngle (AActor *source, PClassActor *type, DAngle angle, do AActor *P_SpawnMissileAngleZ (AActor *source, double z, PClassActor *type, DAngle angle, double vz) { + if (type == nullptr) + { + return nullptr; + } return P_SpawnMissileAngleZSpeed (source, z, type, angle, vz, GetDefaultSpeed (type)); } AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActor *type) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } DAngle an; double dist; @@ -6626,7 +6633,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed) { PARAM_SELF_PROLOGUE(AActor); PARAM_FLOAT(z); - PARAM_OBJECT(dest, AActor); + PARAM_OBJECT_NOT_NULL(dest, AActor); PARAM_CLASS(type, AActor); ACTION_RETURN_OBJECT(P_SpawnMissileZAimed(self, z, dest, type)); } @@ -6643,9 +6650,9 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileZAimed) AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z, PClassActor *type, DAngle angle, double vz, double speed, AActor *owner, bool checkspawn) { - if (source == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } AActor *mo; @@ -6689,9 +6696,9 @@ AActor *P_SpawnSubMissile(AActor *source, PClassActor *type, AActor *target) { AActor *other = Spawn(type, source->Pos(), ALLOW_REPLACE); - if (other == NULL) + if (source == nullptr || type == nullptr) { - return NULL; + return nullptr; } other->target = target; @@ -6723,7 +6730,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnSubMissile) { PARAM_SELF_PROLOGUE(AActor); PARAM_CLASS(cls, AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); ACTION_RETURN_OBJECT(P_SpawnSubMissile(self, cls, target)); } /* @@ -6753,6 +6760,11 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, PClassActor *type, DAngle angle, FTranslatedLineTarget *pLineTarget, AActor **pMissileActor, bool nofreeaim, bool noautoaim, int aimflags) { + if (source == nullptr || type == nullptr) + { + return nullptr; + } + static const double angdiff[3] = { -5.625, 5.625, 0 }; DAngle an = angle; DAngle pitch; @@ -6760,10 +6772,6 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z, AActor *defaultobject = GetDefaultByType(type); DAngle vrange = nofreeaim ? 35. : 0.; - if (source == NULL) - { - return NULL; - } if (!pLineTarget) pLineTarget = &scratch; if (source->player && source->player->ReadyWeapon && ((source->player->ReadyWeapon->WeaponFlags & WIF_NOAUTOAIM) || noautoaim)) { @@ -6910,7 +6918,7 @@ bool AActor::IsTeammate (AActor *other) DEFINE_ACTION_FUNCTION(AActor, isTeammate) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_BOOL(self->IsTeammate(other)); } @@ -6982,7 +6990,7 @@ bool AActor::IsFriend (AActor *other) DEFINE_ACTION_FUNCTION(AActor, isFriend) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_BOOL(self->IsFriend(other)); } @@ -7019,7 +7027,7 @@ bool AActor::IsHostile (AActor *other) DEFINE_ACTION_FUNCTION(AActor, isHostile) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_BOOL(self->IsHostile(other)); } @@ -7058,7 +7066,7 @@ int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) DEFINE_ACTION_FUNCTION(AActor, DoSpecialDamage) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); PARAM_INT(damage); PARAM_NAME(damagetype); ACTION_RETURN_INT(self->DoSpecialDamage(target, damage, damagetype)); @@ -7580,14 +7588,14 @@ DEFINE_ACTION_FUNCTION(AActor, absangle) // should this be global? DEFINE_ACTION_FUNCTION(AActor, Distance2D) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_FLOAT(self->Distance2D(other)); } DEFINE_ACTION_FUNCTION(AActor, Distance3D) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(other, AActor); + PARAM_OBJECT_NOT_NULL(other, AActor); ACTION_RETURN_FLOAT(self->Distance3D(other)); } @@ -7620,7 +7628,7 @@ DEFINE_ACTION_FUNCTION(AActor, GetDefaultByType) { PARAM_PROLOGUE; PARAM_CLASS(cls, AActor); - ACTION_RETURN_OBJECT(GetDefaultByType(cls)); + ACTION_RETURN_OBJECT(cls == nullptr? nullptr : GetDefaultByType(cls)); } DEFINE_ACTION_FUNCTION(AActor, GetBobOffset) @@ -7692,7 +7700,7 @@ DEFINE_ACTION_FUNCTION(AActor, Thrust) DEFINE_ACTION_FUNCTION(AActor, AngleTo) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(targ, AActor); + PARAM_OBJECT_NOT_NULL(targ, AActor); PARAM_BOOL_DEF(absolute); ACTION_RETURN_FLOAT(self->AngleTo(targ, absolute).Degrees); } @@ -7717,7 +7725,7 @@ DEFINE_ACTION_FUNCTION(AActor, RotateVector) DEFINE_ACTION_FUNCTION(AActor, DistanceBySpeed) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(targ, AActor); + PARAM_OBJECT_NOT_NULL(targ, AActor); PARAM_FLOAT(speed); ACTION_RETURN_FLOAT(self->DistanceBySpeed(targ, speed)); } @@ -7745,14 +7753,14 @@ DEFINE_ACTION_FUNCTION(AActor, Vec2Angle) DEFINE_ACTION_FUNCTION(AActor, Vec3To) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(t, AActor) + PARAM_OBJECT_NOT_NULL(t, AActor) ACTION_RETURN_VEC3(self->Vec3To(t)); } DEFINE_ACTION_FUNCTION(AActor, Vec2To) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(t, AActor) + PARAM_OBJECT_NOT_NULL(t, AActor) ACTION_RETURN_VEC2(self->Vec2To(t)); } diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 610ade35a..733741cb2 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1605,38 +1605,40 @@ void player_t::DestroyPSprites() void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) { - - PClassActor *cls = weapon->GetClass(); - while (cls != RUNTIME_CLASS(AWeapon)) + if (flashstate != nullptr) { - if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) + PClassActor *cls = weapon->GetClass(); + while (cls != RUNTIME_CLASS(AWeapon)) { - // The flash state belongs to this class. - // Now let's check if the actually wanted state does also - if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) + if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) { - // we're ok so set the state - P_SetPsprite(player, PSP_FLASH, flashstate + index, true); - return; - } - else - { - // oh, no! The state is beyond the end of the state table so use the original flash state. - P_SetPsprite(player, PSP_FLASH, flashstate, true); - return; + // The flash state belongs to this class. + // Now let's check if the actually wanted state does also + if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) + { + // we're ok so set the state + P_SetPsprite(player, PSP_FLASH, flashstate + index, true); + return; + } + else + { + // oh, no! The state is beyond the end of the state table so use the original flash state. + P_SetPsprite(player, PSP_FLASH, flashstate, true); + return; + } } + // try again with parent class + cls = static_cast(cls->ParentClass); + } + // if we get here the state doesn't seem to belong to any class in the inheritance chain + // This can happen with Dehacked if the flash states are remapped. + // The only way to check this would be to go through all Dehacked modifiable actors, convert + // their states into a single flat array and find the correct one. + // Rather than that, just check to make sure it belongs to something. + if (FState::StaticFindStateOwner(flashstate + index) == NULL) + { // Invalid state. With no index offset, it should at least be valid. + index = 0; } - // try again with parent class - cls = static_cast(cls->ParentClass); - } - // if we get here the state doesn't seem to belong to any class in the inheritance chain - // This can happen with Dehacked if the flash states are remapped. - // The only way to check this would be to go through all Dehacked modifiable actors, convert - // their states into a single flat array and find the correct one. - // Rather than that, just check to make sure it belongs to something. - if (FState::StaticFindStateOwner(flashstate + index) == NULL) - { // Invalid state. With no index offset, it should at least be valid. - index = 0; } P_SetPsprite(player, PSP_FLASH, flashstate + index, true); } @@ -1644,7 +1646,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i DEFINE_ACTION_FUNCTION(_PlayerInfo, SetSafeFlash) { PARAM_SELF_STRUCT_PROLOGUE(player_t); - PARAM_OBJECT(weapon, AWeapon); + PARAM_OBJECT_NOT_NULL(weapon, AWeapon); PARAM_POINTER(state, FState); PARAM_INT(index); P_SetSafeFlash(weapon, self, state, index); diff --git a/src/p_sight.cpp b/src/p_sight.cpp index 319d5b3ec..21aa1bbe3 100644 --- a/src/p_sight.cpp +++ b/src/p_sight.cpp @@ -908,7 +908,7 @@ done: DEFINE_ACTION_FUNCTION(AActor, CheckSight) { PARAM_SELF_PROLOGUE(AActor); - PARAM_OBJECT(target, AActor); + PARAM_OBJECT_NOT_NULL(target, AActor); PARAM_INT_DEF(flags); ACTION_RETURN_BOOL(P_CheckSight(self, target, flags)); } diff --git a/src/p_states.cpp b/src/p_states.cpp index 7daaa5e41..87a1bae2f 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -1083,11 +1083,12 @@ DEFINE_ACTION_FUNCTION(FState, DistanceTo) { PARAM_SELF_STRUCT_PROLOGUE(FState); PARAM_POINTER(other, FState); - - // Safely calculate the distance between two states. - auto o1 = FState::StaticFindStateOwner(self); - int retv; - if (other < o1->OwnedStates || other >= o1->OwnedStates + o1->NumOwnedStates) retv = INT_MIN; - else retv = int(other - self); + int retv = INT_MIN; + if (other != nullptr) + { + // Safely calculate the distance between two states. + auto o1 = FState::StaticFindStateOwner(self); + if (other >= o1->OwnedStates && other < o1->OwnedStates + o1->NumOwnedStates) retv = int(other - self); + } ACTION_RETURN_INT(retv); } diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 20c98acbe..3a2dc6034 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -9697,7 +9697,7 @@ int BuiltinClassCast(VMValue *param, TArray &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) diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 0ccde006f..d105d396c 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -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 at position

+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 &defaultparam, int numparam, VMReturn *ret, int numret);/*(VM_ARGS)*/ diff --git a/src/scripting/vm/vmexec.cpp b/src/scripting/vm/vmexec.cpp index f51038f36..183cc728c 100644 --- a/src/scripting/vm/vmexec.cpp +++ b/src/scripting/vm/vmexec.cpp @@ -228,3 +228,7 @@ void VMFillParams(VMValue *params, VMFrame *callee, int numparam) } } } + +void NullParam(const char *varname) +{ +} \ No newline at end of file