Skip to content

Commit 44f8b09

Browse files
committed
CmdSetup: Fix OOB reads
Using Ghabry's proposed solution. Fixes an Issue similar to #3320
1 parent ab29d95 commit 44f8b09

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

src/game_interpreter.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -647,9 +647,9 @@ bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) {
647647
case Cmd::ChangeHeroTitle:
648648
return CommandChangeHeroTitle(com);
649649
case Cmd::ChangeSpriteAssociation:
650-
return CommandChangeSpriteAssociation(com);
650+
return CmdSetup<&Game_Interpreter::CommandChangeSpriteAssociation, 3>(com);
651651
case Cmd::ChangeActorFace:
652-
return CommandChangeActorFace(com);
652+
return CmdSetup<&Game_Interpreter::CommandChangeActorFace, 4>(com);
653653
case Cmd::ChangeVehicleGraphic:
654654
return CommandChangeVehicleGraphic(com);
655655
case Cmd::ChangeSystemBGM:
@@ -2110,16 +2110,8 @@ bool Game_Interpreter::CommandChangeSpriteAssociation(lcf::rpg::EventCommand con
21102110
}
21112111

21122112
auto file = ToString(CommandStringOrVariableBitfield(com, 3, 1, 4));
2113-
2114-
int idx = 0;
2115-
if (com.parameters.size() > 1) {
2116-
idx = ValueOrVariableBitfield(com, 3, 2, 1);
2117-
}
2118-
2119-
bool transparent = false;
2120-
if (com.parameters.size() > 2) {
2121-
transparent = com.parameters[2] != 0;
2122-
}
2113+
int idx = ValueOrVariableBitfield(com, 3, 2, 1);
2114+
bool transparent = com.parameters[2] != 0;
21232115

21242116
actor->SetSprite(file, idx, transparent);
21252117
Main_Data::game_player->ResetGraphic();
@@ -2129,15 +2121,14 @@ bool Game_Interpreter::CommandChangeSpriteAssociation(lcf::rpg::EventCommand con
21292121
bool Game_Interpreter::CommandChangeActorFace(lcf::rpg::EventCommand const& com) { // code 10640
21302122
int id = ValueOrVariableBitfield(com, 2, 0, 0);
21312123
Game_Actor* actor = Main_Data::game_actors->GetActor(id);
2132-
21332124
if (!actor) {
21342125
Output::Warning("CommandChangeActorFace: Invalid actor ID {}", id);
21352126
return true;
21362127
}
21372128

21382129
actor->SetFace(
2139-
ToString(CommandStringOrVariableBitfield(com, 2, 1, 3)),
2140-
ValueOrVariableBitfield(com, 2, 2, 1));
2130+
ToString(CommandStringOrVariableBitfield(com, 2, 1, 3)),
2131+
ValueOrVariableBitfield(com, 2, 2, 1));
21412132
return true;
21422133
}
21432134

src/game_interpreter_shared.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <lcf/rpg/movecommand.h>
2424
#include <lcf/rpg/saveeventexecframe.h>
2525
#include <string_view.h>
26+
#include "compiler.h"
2627

2728
class Game_Character;
2829
class Game_BaseInterpreterContext;
@@ -167,6 +168,25 @@ class Game_BaseInterpreterContext {
167168
inline int ValueOrVariableBitfield(lcf::rpg::EventCommand const& com, int mode_idx, int shift, int val_idx) const {
168169
return Game_Interpreter_Shared::ValueOrVariableBitfield<validate_patches, support_indirect_and_switch, support_scopes, support_named>(com, mode_idx, shift, val_idx, *this);
169170
}
171+
172+
template<typename RetType, typename ClsType, typename... Args>
173+
ClsType MemFnCls(RetType(ClsType::*)(Args...));
174+
175+
template<auto CMDFN, size_t MIN_SIZE>
176+
bool CmdSetup(lcf::rpg::EventCommand const& com) {
177+
using ClassType = decltype(MemFnCls(CMDFN));
178+
179+
if (EP_UNLIKELY(com.parameters.size() < MIN_SIZE)) {
180+
// Slow resizing of the parameters
181+
// Only happens for malformed commands
182+
auto ncom = com;
183+
ncom.parameters = lcf::DBArray<int32_t>(MIN_SIZE);
184+
std::copy(com.parameters.begin(), com.parameters.end(), ncom.parameters.begin());
185+
return (static_cast<ClassType*>(this)->*CMDFN)(ncom);
186+
}
187+
188+
return (static_cast<ClassType*>(this)->*CMDFN)(com);
189+
}
170190
};
171191

172192
#endif

0 commit comments

Comments
 (0)