Fix several more possible crashes from the Lua API

This commit is contained in:
MysterD 2023-05-15 15:55:16 -07:00
parent ed163203d8
commit 60d70d0d38
28 changed files with 87 additions and 47 deletions

View file

@ -952,9 +952,17 @@ ifeq ($(WINDOWS_BUILD),999)
endif
ifeq ($(ASAN),1)
ifeq ($(COMPILER),gcc)
EXTRA_CFLAGS += -fsanitize=address -fsanitize=bounds-strict -fsanitize=undefined -ggdb
EXTRA_CPP_FLAGS += -fsanitize=address -fsanitize=bounds-strict -fsanitize=undefined -ggdb
LDFLAGS += -fsanitize=address -fsanitize=bounds-strict -fsanitize=undefined -static-libasan
else ifeq ($(COMPILER),clang)
EXTRA_CFLAGS += -fsanitize=address -fsanitize=undefined -ggdb
EXTRA_CPP_FLAGS += -fsanitize=address -fsanitize=undefined -ggdb
LDFLAGS += -fsanitize=address -fsanitize=undefined
endif
endif
# Coop specific libraries

View file

@ -93,7 +93,7 @@ override_field_immutable = {
"GlobalObjectAnimations": [ "*"],
"SpawnParticlesInfo": [ "model" ],
"MarioBodyState": [ "updateTorsoTime" ],
"Area": [ "localAreaTimer", "nextSyncID", "unk04" ],
"Area": [ "localAreaTimer", "nextSyncID", "unk04", "objectSpawnInfos", "paintingWarpNodes", "warpNodes" ],
"Mod": [ "*" ],
"ModFile": [ "*" ],
"BassAudio": [ "*" ],

View file

@ -84,6 +84,9 @@ void DynOS_Anim_Swap(void *aPtr) {
if (_AnimIndex == -1) {
return;
}
if (_AnimIndex >= _GfxData->mAnimationTable.Count()) {
return;
}
// Animation data
const AnimData *_AnimData = (const AnimData *) _GfxData->mAnimationTable[_AnimIndex].second;

View file

@ -13,7 +13,8 @@ struct ScheduledFreePool {
};
static struct DynamicPool* sModelPools[MODEL_POOL_MAX] = { 0 };
static std::map<void*, struct GraphNode*> sModelMap[MODEL_POOL_MAX];
static std::map<void*, struct GraphNode*> sGraphNodeMap[MODEL_POOL_MAX];
static std::map<u32, struct GraphNode*> sModelIdMap;
static std::vector<struct ScheduledFreePool> sPoolsToFree;
struct GraphNode* DynOS_Model_LoadGeo(enum ModelPool aModelPool, void* aAsset) {
@ -26,7 +27,7 @@ struct GraphNode* DynOS_Model_LoadGeo(enum ModelPool aModelPool, void* aAsset) {
}
// check map
auto& map = sModelMap[aModelPool];
auto& map = sGraphNodeMap[aModelPool];
if (map.count(aAsset)) {
return map[aAsset];
}
@ -49,7 +50,7 @@ struct GraphNode* DynOS_Model_LoadDl(enum ModelPool aModelPool, u8 aLayer, void*
}
// check map
auto& map = sModelMap[aModelPool];
auto& map = sGraphNodeMap[aModelPool];
if (map.count(aAsset)) {
return map[aAsset];
}
@ -75,7 +76,7 @@ void DynOS_Model_ClearPool(enum ModelPool aModelPool) {
sModelPools[aModelPool] = NULL;
// clear map
auto& map = sModelMap[aModelPool];
auto& map = sGraphNodeMap[aModelPool];
map.clear();
}

View file

@ -145,12 +145,12 @@
| nextSyncID | `integer` | read-only |
| numRedCoins | `integer` | |
| numSecrets | `integer` | |
| objectSpawnInfos | [SpawnInfo](structs.md#SpawnInfo) | |
| paintingWarpNodes | [WarpNode](structs.md#WarpNode) | |
| objectSpawnInfos | [SpawnInfo](structs.md#SpawnInfo) | read-only |
| paintingWarpNodes | [WarpNode](structs.md#WarpNode) | read-only |
| surfaceRooms | `Pointer` <`integer`> | read-only |
| terrainData | `Pointer` <`integer`> | read-only |
| terrainType | `integer` | |
| warpNodes | [ObjectWarpNode](structs.md#ObjectWarpNode) | |
| warpNodes | [ObjectWarpNode](structs.md#ObjectWarpNode) | read-only |
[:arrow_up_small:](#)

View file

@ -1064,6 +1064,7 @@ void audio_list_push_front(struct AudioListItem *list, struct AudioListItem *ite
}
void audio_list_remove(struct AudioListItem *item) {
if (!item) { return; }
// remove 'item' from the list it's in, if any
if (item->prev == NULL) {
eu_stubbed_printf_0("Already Cut\n");

View file

@ -25,7 +25,9 @@ static void handle_merry_go_round_music(void) {
struct Object *marioObject = gMarioObjects[0];
u16 marioFloorType = 0;
if (marioObject) {
find_floor(marioObject->oPosX, marioObject->oPosY, marioObject->oPosZ, &marioFloor);
}
if (marioFloor != NULL) {
marioFloorType = marioFloor->type;

View file

@ -130,7 +130,7 @@ static void beta_boo_key_drop(void) {
// Make the key move laterally away from Mario at 3 units/frame
// (as if he transferred kinetic energy to it)
velocityDirection = gMarioObject->oMoveAngleYaw;
velocityDirection = gMarioObject ? gMarioObject->oMoveAngleYaw : 0;
velocityMagnitude = 3.0f;
o->oVelX = sins(velocityDirection) * velocityMagnitude;

View file

@ -75,7 +75,7 @@ void bhv_beta_trampoline_top_loop(void) {
// Since the trampoline never moves, this doesn't do anything.
// Maybe they intended to decrease the trampoline's position
// when Mario's on it in this if statement?
if (gMarioObject->platform == o) {
if (gMarioObject && gMarioObject->platform == o) {
o->oBetaTrampolineMarioOnTrampoline = TRUE;
} else {
o->oBetaTrampolineMarioOnTrampoline = FALSE;

View file

@ -135,7 +135,7 @@ void bhv_blue_coin_switch_loop(void) {
case BLUE_COIN_SWITCH_ACT_IDLE:
// If Mario is on the switch and has ground-pounded,
// recede and get ready to start ticking.
if (gMarioObject->platform == o) {
if (gMarioObject && gMarioObject->platform == o) {
if (determine_interaction(&gMarioStates[0], o) & INT_GROUND_POUND) {
// Set to BLUE_COIN_SWITCH_ACT_RECEDING
o->oAction++;
@ -164,7 +164,9 @@ void bhv_blue_coin_switch_loop(void) {
// Set to BLUE_COIN_SWITCH_ACT_TICKING
o->oAction++;
// ???
if (gMarioObject) {
o->oPosY = gMarioObject->oPosY - 40.0f;
}
// Spawn particles. There's a function that calls this same function
// with the same arguments, spawn_mist_particles, why didn't they just call that?

View file

@ -1029,7 +1029,7 @@ void bhv_boo_in_castle_loop(void) {
}
void bhv_boo_boss_spawned_bridge_loop(void) {
f32 targetY;
f32 targetY = 0;
switch (o->oBehParams2ndByte) {
case 1:

View file

@ -75,7 +75,7 @@ void opened_cannon_act_6(void) {
o->oMoveAngleYaw = sins(o->oCannonUnkF4) * 0x4000 + ((s16)(o->oBehParams2ndByte << 8));
o->oCannonUnkF4 += 0x400;
} else if (o->oTimer < 26) {
} else if (o->oCannonPlayerIndex < MAX_PLAYERS) {
} else if (o->oCannonPlayerIndex >= 0 && o->oCannonPlayerIndex < MAX_PLAYERS) {
struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
if (controlledBy && controlledBy->marioObj != NULL) {
controlledBy->marioObj->oMarioCannonObjectYaw = o->oMoveAngleYaw;
@ -110,7 +110,7 @@ void opened_cannon_act_1(void) {
if (o->oCannonPlayerIndex == 0) {
cur_obj_become_intangible();
cur_obj_disable_rendering();
} else if (o->oCannonPlayerIndex < MAX_PLAYERS) {
} else if (o->oCannonPlayerIndex >= 0 && o->oCannonPlayerIndex < MAX_PLAYERS) {
struct MarioState* controlledBy = &gMarioStates[o->oCannonPlayerIndex];
o->oMoveAnglePitch = 14563 + controlledBy->faceAngle[0] * -0.5f;
if (controlledBy->marioObj != NULL) {

View file

@ -450,7 +450,6 @@ static void chain_chomp_act_move(void) {
*/
static void chain_chomp_act_unload_chain(void) {
cur_obj_hide();
dynamic_pool_free(gLevelPool, o->oChainChompSegments);
o->oAction = CHAIN_CHOMP_ACT_UNINITIALIZED;

View file

@ -244,7 +244,7 @@ void coin_inside_boo_act_0(void) {
obj_copy_pos(o, parent);
if (parent->oBooDeathStatus == BOO_DEATH_STATUS_DYING) {
o->oAction = 1;
s16 sp26 = gMarioObject->oMoveAngleYaw;
s16 sp26 = gMarioObject ? gMarioObject->oMoveAngleYaw : 0;
f32 sp20 = 3.0f;
o->oVelX = sins(sp26) * sp20;
o->oVelZ = coss(sp26) * sp20;

View file

@ -8,7 +8,9 @@ void bhv_hidden_star_init(void) {
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}
if (gCurrentArea) {
o->oHiddenStarTriggerCounter = gCurrentArea->numSecrets - count;
}
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
@ -34,7 +36,7 @@ void bhv_hidden_star_init(void) {
void bhv_hidden_star_loop(void) {
switch (o->oAction) {
case 0:
if (o->oHiddenStarTriggerCounter >= gCurrentArea->numSecrets) {
if (gCurrentArea && o->oHiddenStarTriggerCounter >= gCurrentArea->numSecrets) {
o->oAction = 1;
}
break;
@ -63,7 +65,9 @@ void bhv_hidden_star_trigger_loop(void) {
if (hiddenStar != NULL) {
s16 count = (count_objects_with_behavior(bhvHiddenStarTrigger) - 1);
if (gCurrentArea) {
hiddenStar->oHiddenStarTriggerCounter = gCurrentArea->numSecrets - count;
}
spawn_orange_number(hiddenStar->oHiddenStarTriggerCounter, 0, 0, 0);
// Set the last person who interacted with a secret to the
@ -98,7 +102,7 @@ void bhv_hidden_star_trigger_loop(void) {
void bhv_bowser_course_red_coin_star_loop(void) {
switch (o->oAction) {
case 0:
if (o->oHiddenStarTriggerCounter >= gCurrentArea->numRedCoins) {
if (gCurrentArea && o->oHiddenStarTriggerCounter >= gCurrentArea->numRedCoins) {
o->oAction = 1;
}
break;

View file

@ -39,8 +39,9 @@ void bhv_ship_part_3_loop(void) {
o->oFaceAngleRoll = sins(o->oShipPart3UnkF8) * 1024.0f;
o->oAngleVelPitch = o->oFaceAnglePitch - sp1E;
o->oAngleVelRoll = o->oFaceAngleRoll - sp1C;
if (gMarioObject->oPosY > 1000.0f)
if (gMarioObject && gMarioObject->oPosY > 1000.0f) {
cur_obj_play_sound_1(SOUND_ENV_BOAT_ROCKING1);
}
}
void bhv_jrb_sliding_box_loop(void) {
@ -103,13 +104,18 @@ void bhv_jrb_sliding_box_loop(void) {
o->oJrbSlidingBoxUnkFC = sins(o->oJrbSlidingBoxUnkF8) * 20.0f;
o->oJrbSlidingBoxUnkF8 += 0x100;
o->oParentRelativePosZ += o->oJrbSlidingBoxUnkFC;
if (gMarioObject->oPosY > 1000.0f)
if (absf(o->oJrbSlidingBoxUnkFC) > 3.0f)
if (gMarioObject && gMarioObject->oPosY > 1000.0f) {
if (absf(o->oJrbSlidingBoxUnkFC) > 3.0f) {
cur_obj_play_sound_1(SOUND_AIR_ROUGH_SLIDE);
}
}
obj_set_hitbox(o, &sSkullSlidingBoxHitbox);
if (!(o->oJrbSlidingBoxUnkF8 & 0x7FFF))
if (!(o->oJrbSlidingBoxUnkF8 & 0x7FFF)) {
cur_obj_become_tangible();
if (obj_check_if_collided_with_object(o, gMarioObject)) {
}
if (gMarioObject && obj_check_if_collided_with_object(o, gMarioObject)) {
o->oInteractStatus = 0;
cur_obj_become_intangible();
}

View file

@ -2,9 +2,11 @@
void bhv_pole_base_loop(void) {
if (!gMarioObject) { return; }
if (o->oPosY - 10.0f < gMarioObject->oPosY
&& gMarioObject->oPosY < o->oPosY + o->hitboxHeight + 30.0f)
if (o->oTimer > 10)
if (!(gMarioStates[0].action & MARIO_PUNCHING))
if (o->oPosY - 10.0f < gMarioObject->oPosY && gMarioObject->oPosY < o->oPosY + o->hitboxHeight + 30.0f) {
if (o->oTimer > 10) {
if (!(gMarioStates[0].action & MARIO_PUNCHING)) {
cur_obj_push_mario_away(70.0f);
}
}
}
}

View file

@ -31,7 +31,7 @@ void bhv_purple_switch_loop(void) {
case PURPLE_SWITCH_IDLE:
cur_obj_set_model(smlua_model_util_load(E_MODEL_PURPLE_SWITCH));
cur_obj_scale(1.5f);
if (gMarioObject->platform == o && !(gMarioStates[0].action & MARIO_UNKNOWN_13)) {
if (gMarioObject && gMarioObject->platform == o && !(gMarioStates[0].action & MARIO_UNKNOWN_13)) {
if (lateral_dist_between_objects(o, gMarioObject) < 127.5) {
o->oAction = PURPLE_SWITCH_PRESSED;
network_send_object(o);

View file

@ -50,7 +50,9 @@ void bhv_red_coin_loop(void) {
// ...and there is a red coin star in the level...
if (o->parentObj != NULL) {
s16 redCoins = count_objects_with_behavior(bhvRedCoin) - 1;
if (gCurrentArea) {
o->parentObj->oHiddenStarTriggerCounter = gCurrentArea->numRedCoins - redCoins;
}
// Set the last person who interacted with a red coin to the
// parent so only they get the star cutscene.

View file

@ -288,7 +288,9 @@ void bhv_hidden_red_coin_star_init(void) {
o->activeFlags = ACTIVE_FLAG_DEACTIVATED;
}
if (gCurrentArea) {
o->oHiddenStarTriggerCounter = gCurrentArea->numRedCoins - redCoins;
}
// We haven't interacted with a player yet.
// We also don't sync this as not only is it not required
@ -313,7 +315,7 @@ void bhv_hidden_red_coin_star_init(void) {
void bhv_hidden_red_coin_star_loop(void) {
switch (o->oAction) {
case 0:
if (o->oHiddenStarTriggerCounter >= gCurrentArea->numRedCoins) {
if (gCurrentArea && o->oHiddenStarTriggerCounter >= gCurrentArea->numRedCoins) {
o->oAction = 1;
}
break;

View file

@ -21,7 +21,7 @@ void bhv_wf_elevator_tower_platform_loop(void) {
switch (o->oAction) {
case 0:
if (gMarioObject->platform == o) {
if (gMarioObject && gMarioObject->platform == o) {
o->oAction++;
network_send_object(o);
}

View file

@ -66,7 +66,13 @@ void bhv_ttc_treadmill_update(void) {
approach_f32_ptr(&o->oTTCTreadmillSpeed, o->oTTCTreadmillTargetSpeed, 10.0f);
}
*o->oTTCTreadmillBigSurface = *o->oTTCTreadmillSmallSurface = o->oTTCTreadmillSpeed;
if (o->oTTCTreadmillSmallSurface) {
*o->oTTCTreadmillSmallSurface = o->oTTCTreadmillSpeed;
}
if (o->oTTCTreadmillBigSurface) {
*o->oTTCTreadmillBigSurface = o->oTTCTreadmillSpeed;
}
}
}

View file

@ -5429,7 +5429,7 @@ void warp_camera(f32 displacementX, f32 displacementY, f32 displacementZ) {
struct LinearTransitionPoint *start = &sModeInfo.transitionStart;
struct LinearTransitionPoint *end = &sModeInfo.transitionEnd;
gCurrLevelArea = gCurrLevelNum * 16 + gCurrentArea->index;
gCurrLevelArea = gCurrLevelNum * 16 + (gCurrentArea ? gCurrentArea->index : 0);
displacement[0] = displacementX;
displacement[1] = displacementY;
displacement[2] = displacementZ;

View file

@ -865,6 +865,7 @@ void update_mario_sound_and_camera(struct MarioState *m) {
// only update for local player
if (m != &gMarioStates[0]) { return; }
if (!m->area || !m->area->camera) { return; }
u32 action = m->action;
s32 camPreset = m->area->camera->mode;
@ -1332,7 +1333,7 @@ s32 check_common_hold_action_exits(struct MarioState *m) {
*/
s32 transition_submerged_to_walking(struct MarioState *m) {
if (!m) { return FALSE; }
if (m->playerIndex == 0) {
if (m->playerIndex == 0 && m->area && m->area->camera) {
set_camera_mode(m->area->camera, m->area->camera->defMode, 1);
}

View file

@ -3049,8 +3049,7 @@ static s32 check_for_instant_quicksand(struct MarioState *m) {
}
if (m->action == ACT_BUBBLED) { return FALSE; }
if (m->floor->type == SURFACE_INSTANT_QUICKSAND && m->action & ACT_FLAG_INVULNERABLE
&& m->action != ACT_QUICKSAND_DEATH && m->action != ACT_SHOCKED) {
if (m->floor && m->floor->type == SURFACE_INSTANT_QUICKSAND && m->action & ACT_FLAG_INVULNERABLE && m->action != ACT_QUICKSAND_DEATH && m->action != ACT_SHOCKED) {
update_mario_sound_and_camera(m);
return drop_and_set_mario_action(m, ACT_QUICKSAND_DEATH, 0);
}

View file

@ -696,6 +696,7 @@ void anim_and_audio_for_hold_walk(struct MarioState *m) {
break;
default:
val08 = FALSE;
break;
}
}

View file

@ -147,6 +147,7 @@ void apply_water_current(struct MarioState *m, Vec3f step) {
step[2] += currentSpeed * coss(currentAngle);
}
if (!gCurrentArea) { return; }
for (i = 0; i < 2; i++) {
struct Whirlpool *whirlpool = gCurrentArea->whirlpools[i];
if (whirlpool != NULL) {

View file

@ -72,14 +72,14 @@ static struct LuaObjectField sAreaFields[LUA_AREA_FIELD_COUNT] = {
{ "nextSyncID", LVT_U32, offsetof(struct Area, nextSyncID), true, LOT_NONE },
{ "numRedCoins", LVT_U8, offsetof(struct Area, numRedCoins), false, LOT_NONE },
{ "numSecrets", LVT_U8, offsetof(struct Area, numSecrets), false, LOT_NONE },
{ "objectSpawnInfos", LVT_COBJECT_P, offsetof(struct Area, objectSpawnInfos), false, LOT_SPAWNINFO },
{ "paintingWarpNodes", LVT_COBJECT_P, offsetof(struct Area, paintingWarpNodes), false, LOT_WARPNODE },
{ "objectSpawnInfos", LVT_COBJECT_P, offsetof(struct Area, objectSpawnInfos), true, LOT_SPAWNINFO },
{ "paintingWarpNodes", LVT_COBJECT_P, offsetof(struct Area, paintingWarpNodes), true, LOT_WARPNODE },
{ "surfaceRooms", LVT_S8_P, offsetof(struct Area, surfaceRooms), true, LOT_POINTER },
{ "terrainData", LVT_S16_P, offsetof(struct Area, terrainData), true, LOT_POINTER },
{ "terrainType", LVT_U16, offsetof(struct Area, terrainType), false, LOT_NONE },
// { "unk04", LVT_COBJECT_P, offsetof(struct Area, unk04), true, LOT_??? }, <--- UNIMPLEMENTED
// { "unused28", LVT_COBJECT_P, offsetof(struct Area, unused28), false, LOT_??? }, <--- UNIMPLEMENTED
{ "warpNodes", LVT_COBJECT_P, offsetof(struct Area, warpNodes), false, LOT_OBJECTWARPNODE },
{ "warpNodes", LVT_COBJECT_P, offsetof(struct Area, warpNodes), true, LOT_OBJECTWARPNODE },
// { "whirlpools", LOT_???, offsetof(struct Area, whirlpools), false, LOT_??? }, <--- UNIMPLEMENTED
};