Skip to content

Commit 6ad4b22

Browse files
committed
Engine: add object and char assertions in Get/SetProperty functions
Since older commit 5f3b8eb the properties are stored in vectors, strictly resized to the number of characters and objects. But the script functions that access these do not do any assertion whether the object or char is valid, which could cause bad mem access in case script loops over a array of objects of MAX_OBJECTS size, or tries to access something using Object* pointer from another room.
1 parent b7e2248 commit 6ad4b22

File tree

5 files changed

+61
-17
lines changed

5 files changed

+61
-17
lines changed

Engine/ac/character.cpp

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ int numLipLines = 0, curLipLine = -1, curLipLinePhoneme = 0;
103103

104104
// **** CHARACTER: FUNCTIONS ****
105105

106+
bool is_valid_character(int char_id)
107+
{
108+
return ((char_id >= 0) && (char_id < game.numcharacters));
109+
}
110+
111+
bool AssertCharacter(const char *apiname, int char_id)
112+
{
113+
if ((char_id >= 0) && (char_id < game.numcharacters))
114+
return true;
115+
debug_script_warn("%s: invalid character id %d (range is 0..%d)", apiname, char_id, game.numcharacters - 1);
116+
return false;
117+
}
118+
106119
void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addIndex) {
107120
int ee;
108121

@@ -1050,25 +1063,38 @@ void Character_RunInteraction(CharacterInfo *chaa, int mood) {
10501063

10511064
// **** CHARACTER: PROPERTIES ****
10521065

1053-
int Character_GetProperty(CharacterInfo *chaa, const char *property) {
1054-
1066+
int Character_GetProperty(CharacterInfo *chaa, const char *property)
1067+
{
1068+
if (!AssertCharacter("Character.GetProperty", chaa->index_id))
1069+
return 0;
10551070
return get_int_property(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property);
1056-
10571071
}
1058-
void Character_GetPropertyText(CharacterInfo *chaa, const char *property, char *bufer) {
1072+
1073+
void Character_GetPropertyText(CharacterInfo *chaa, const char *property, char *bufer)
1074+
{
1075+
if (!AssertCharacter("Character.GetPropertyText", chaa->index_id))
1076+
return;
10591077
get_text_property(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property, bufer);
10601078
}
1061-
const char* Character_GetTextProperty(CharacterInfo *chaa, const char *property) {
1079+
1080+
const char* Character_GetTextProperty(CharacterInfo *chaa, const char *property)
1081+
{
1082+
if (!AssertCharacter("Character.GetTextProperty", chaa->index_id))
1083+
return nullptr;
10621084
return get_text_property_dynamic_string(game.charProps[chaa->index_id], play.charProps[chaa->index_id], property);
10631085
}
10641086

10651087
bool Character_SetProperty(CharacterInfo *chaa, const char *property, int value)
10661088
{
1089+
if (!AssertCharacter("Character.SetProperty", chaa->index_id))
1090+
return false;
10671091
return set_int_property(play.charProps[chaa->index_id], property, value);
10681092
}
10691093

10701094
bool Character_SetTextProperty(CharacterInfo *chaa, const char *property, const char *value)
10711095
{
1096+
if (!AssertCharacter("Character.SetTextProperty", chaa->index_id))
1097+
return false;
10721098
return set_text_property(play.charProps[chaa->index_id], property, value);
10731099
}
10741100

@@ -2028,11 +2054,6 @@ void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int
20282054

20292055
}
20302056

2031-
int is_valid_character(int newchar) {
2032-
if ((newchar < 0) || (newchar >= game.numcharacters)) return 0;
2033-
return 1;
2034-
}
2035-
20362057
int wantMoveNow (CharacterInfo *chi, CharacterExtras *chex) {
20372058
// check most likely case first
20382059
if ((chex->zoom == 100) || ((chi->flags & CHF_SCALEMOVESPEED) == 0))

Engine/ac/character.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828

2929
// **** CHARACTER: FUNCTIONS ****
3030

31+
bool is_valid_character(int char_id);
32+
// Asserts the character ID is valid,
33+
// if not then prints a warning to the log; returns assertion result
34+
bool AssertCharacter(const char *apiname, int char_id);
35+
3136
void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addIndex);
3237
void Character_AddWaypoint(CharacterInfo *chaa, int x, int y);
3338
void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat,
@@ -186,7 +191,6 @@ void find_nearest_walkable_area (int *xx, int *yy);
186191
void walk_character(int chac,int tox,int toy,int ignwal, bool autoWalkAnims);
187192
void FindReasonableLoopForCharacter(CharacterInfo *chap);
188193
void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int direct, bool isWalk);
189-
int is_valid_character(int newchar);
190194
int wantMoveNow (CharacterInfo *chi, CharacterExtras *chex);
191195
void setup_player_character(int charid);
192196
Common::Bitmap *GetCharacterImage(int charid, bool *is_original = nullptr);

Engine/ac/global_object.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,8 @@ int GetObjectProperty (int hss, const char *property)
545545

546546
void GetObjectPropertyText (int item, const char *property, char *bufer)
547547
{
548+
if (!AssertObject("GetObjectPropertyText", item))
549+
return;
548550
get_text_property(thisroom.Objects[item].Properties, croom->objProps[item], property, bufer);
549551
}
550552

Engine/ac/object.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ extern IGraphicsDriver *gfxDriver;
5454
extern CCObject ccDynamicObject;
5555

5656

57+
bool is_valid_object(int obj_id)
58+
{
59+
return (obj_id >= 0) && (static_cast<uint32_t>(obj_id) < croom->numobj);
60+
}
61+
62+
bool AssertObject(const char *apiname, int obj_id)
63+
{
64+
if ((obj_id >= 0) && (static_cast<uint32_t>(obj_id) < croom->numobj))
65+
return true;
66+
debug_script_warn("%s: invalid object id %d (range is 0..%d)", apiname, obj_id, croom->numobj - 1);
67+
return false;
68+
}
69+
5770
int Object_IsCollidingWithObject(ScriptObject *objj, ScriptObject *obj2) {
5871
return AreObjectsColliding(objj->id, obj2->id);
5972
}
@@ -73,11 +86,6 @@ ScriptObject *GetObjectAtRoom(int x, int y)
7386
return &scrObj[hsnum];
7487
}
7588

76-
int is_valid_object(int obtest) {
77-
if ((obtest < 0) || (static_cast<uint32_t>(obtest) >= croom->numobj)) return 0;
78-
return 1;
79-
}
80-
8189
void Object_Tint(ScriptObject *objj, int red, int green, int blue, int saturation, int luminance) {
8290
SetObjectTint(objj->id, red, green, blue, saturation, luminance);
8391
}
@@ -459,16 +467,22 @@ void Object_GetPropertyText(ScriptObject *objj, const char *property, char *bufe
459467

460468
const char* Object_GetTextProperty(ScriptObject *objj, const char *property)
461469
{
470+
if (!AssertObject("Object.GetTextProperty", objj->id))
471+
return nullptr;
462472
return get_text_property_dynamic_string(thisroom.Objects[objj->id].Properties, croom->objProps[objj->id], property);
463473
}
464474

465475
bool Object_SetProperty(ScriptObject *objj, const char *property, int value)
466476
{
477+
if (!AssertObject("Object.SetProperty", objj->id))
478+
return false;
467479
return set_int_property(croom->objProps[objj->id], property, value);
468480
}
469481

470482
bool Object_SetTextProperty(ScriptObject *objj, const char *property, const char *value)
471483
{
484+
if (!AssertObject("Object.SetTextProperty", objj->id))
485+
return false;
472486
return set_text_property(croom->objProps[objj->id], property, value);
473487
}
474488

Engine/ac/object.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
namespace AGS { namespace Common { class Bitmap; } }
2727
using namespace AGS; // FIXME later
2828

29-
int is_valid_object(int obtest);
29+
bool is_valid_object(int obj_id);
30+
// Asserts the object ID is valid in the current room,
31+
// if not then prints a warning to the log; returns assertion result
32+
bool AssertObject(const char *apiname, int obj_id);
3033
int Object_IsCollidingWithObject(ScriptObject *objj, ScriptObject *obj2);
3134
ScriptObject *GetObjectAtScreen(int xx, int yy);
3235
void Object_Tint(ScriptObject *objj, int red, int green, int blue, int saturation, int luminance);

0 commit comments

Comments
 (0)