Skip to content

Commit

Permalink
Fix unsafe player access in UpdatePadState
Browse files Browse the repository at this point in the history
We should *not* access the global context or the player actor manually
in UpdatePadState because neither are guaranteed to still exist in
memory when that function is called.

Fixes random crashes if ZR is held during a transition (transitions
usually involve destructing the current game state and then
reinitialising again -- the global context may be reallocated at a
different location). Closes #146.
  • Loading branch information
leoetlino committed Jan 2, 2022
1 parent f462a56 commit 0930f3f
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 6 deletions.
1 change: 1 addition & 0 deletions source/common/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ struct Context {

bool going_back_in_time = false;

bool is_swimming = false;
bool use_fast_swim = true;
u32 a_press_duration = 0;
};
Expand Down
9 changes: 3 additions & 6 deletions source/rst/input.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#include "common/context.h"
#include "game/common_data.h"
#include "game/context.h"
#include "game/pad.h"
#include "game/player.h"
#include "game/ui.h"

namespace rst {
Expand Down Expand Up @@ -34,10 +32,9 @@ RST_HOOK void UpdatePadState() {

if (state.input.buttons.IsSet(pad::Button::ZR)) {
// XXX: This shouldn't be here...
auto* gctx = rst::GetContext().gctx;
auto* player = gctx ? gctx->GetPlayerActor() : nullptr;
if (player && player->flags1.IsSet(game::act::Player::Flag1::InWater) &&
!player->flags_94.IsSet(game::act::Actor::Flag94::Grounded)) {
// Note that we do *not* access the global context or the player actor here manually,
// because neither are guaranteed to still exist in memory when this function is called.
if (GetContext().is_swimming) {
// If Link is swimming (as Zora Link most likely but that doesn't matter),
// do not unset the A button.
set_touch_btn_without_clear(pad::Button::A, pad::TouchscreenButton::Ocarina);
Expand Down
6 changes: 6 additions & 0 deletions source/rst/link.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ static void HandleFastOcarina(game::GlobalContext* gctx) {
}

void Calc() {
GetContext().is_swimming = false;
game::GlobalContext* gctx = GetContext().gctx;
game::act::Player* player = gctx->GetPlayerActor();
if (!player)
Expand All @@ -279,6 +280,11 @@ void Calc() {
GetContext().a_press_duration = 0;
}

if (player->flags1.IsSet(game::act::Player::Flag1::InWater) &&
!player->flags_94.IsSet(game::act::Actor::Flag94::Grounded)) {
GetContext().is_swimming = true;
}

HandleFastArrowSwitch(player);
HandleFastOcarina(gctx);
}
Expand Down

0 comments on commit 0930f3f

Please sign in to comment.