Skip to content

Commit 306f34a

Browse files
authored
update force_fit_string and bounds in calling functions (#7161)
Rewrite `force_fit_string` to be more robust and to remove the potential for memory access violations. Also audit all of the length parameters in the calling functions - some of them were the buffer size, not the length. This should fix the mysterious crash in the mission log screen.
1 parent fb52a88 commit 306f34a

10 files changed

Lines changed: 89 additions & 26 deletions

File tree

code/graphics/software/font.cpp

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -559,24 +559,45 @@ namespace font
559559
font_initialized = false;
560560
}
561561

562-
int force_fit_string(char *str, int max_str, int max_width, float scale)
562+
int force_fit_string(char *str, size_t max_str_len, int max_width, float scale)
563563
{
564-
int w;
564+
if (max_width <= 0 || max_str_len == 0) {
565+
*str = 0;
566+
return 0;
567+
}
568+
569+
size_t len = strlen(str);
570+
if (len > max_str_len) {
571+
len = max_str_len;
572+
str[len] = 0;
573+
}
565574

575+
int w;
566576
gr_get_string_size(&w, nullptr, str, scale);
567577
if (w > max_width) {
568-
if ((int)strlen(str) > max_str - 3) {
569-
Assert(max_str >= 3);
570-
str[max_str - 3] = 0;
578+
constexpr char ellipsis_char = '.';
579+
constexpr size_t ellipsis_len = 3;
580+
581+
// make sure an ellipsis will fit
582+
if (len < ellipsis_len) {
583+
*str = 0;
584+
return 0;
571585
}
572586

573-
strcpy(str + strlen(str) - 1, "...");
574-
gr_get_string_size(&w, nullptr, str, scale);
575-
while (w > max_width) {
576-
Assert(strlen(str) >= 4); // if this is hit, a bad max_width was passed in and the calling function needs fixing.
577-
strcpy(str + strlen(str) - 4, "...");
578-
gr_get_string_size(&w, nullptr, str, scale);
587+
// replace the last few chars with an ellipsis
588+
for (size_t i = 0; i < ellipsis_len; ++i) {
589+
--len;
590+
str[len] = ellipsis_char;
579591
}
592+
593+
// move the ellipsis back until the whole string fits
594+
while (len > 0 && w > max_width) {
595+
--len;
596+
str[len] = ellipsis_char;
597+
gr_get_string_size(&w, nullptr, str, scale, len + ellipsis_len);
598+
};
599+
600+
str[len + ellipsis_len] = 0;
580601
}
581602

582603
return w;

code/graphics/software/font.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ namespace font
2727
* Does this by dropping characters at the end of the string and adding '...' to the end.
2828
*
2929
* @param str string to crop. Modifies this string directly
30-
* @param max_str max characters allowed in str
30+
* @param max_str_len max characters allowed in str (not including \0)
3131
* @param max_width number of pixels to limit string to (less than or equal to).
3232
* @return The width of the string
3333
*/
34-
int force_fit_string(char *str, int max_str, int max_width, float scale = 1.0f);
34+
int force_fit_string(char *str, size_t max_str_len, int max_width, float scale = 1.0f);
3535

3636
/**
3737
* @brief Inites the font system

code/hud/hudescort.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ void HudGaugeEscort::renderIcon(int x, int y, int index, float scale, bool confi
382382
// print out ship name
383383
// original behavior replaced with similar logic to hudtargetbox.cpp, except
384384
// if the name is hidden, it's replaced with the class name.
385-
char buf[255];
385+
char buf[256];
386386
if (!config) {
387387
if (((Iff_info[sp->team].flags & IFFF_WING_NAME_HIDDEN) && (sp->wingnum != -1)) ||
388388
(sp->flags[Ship::Ship_Flags::Hide_ship_name])) {
@@ -474,7 +474,7 @@ void HudGaugeEscort::renderIcon(int x, int y, int index, float scale, bool confi
474474
void HudGaugeEscort::renderIconDogfight(int x, int y, int index)
475475
{
476476
int hull_integrity = 100;
477-
char buf[255];
477+
char buf[256];
478478
int np_index;
479479
object *objp;
480480

code/hud/hudsquadmsg.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2934,7 +2934,7 @@ void HudGaugeSquadMessage::render(float /*frametime*/, bool config)
29342934
for (int i = 0; i < nitems; i++ ) {
29352935
int item_num;
29362936
bool isSelectedItem = (i == Selected_menu_item);
2937-
char text[255];
2937+
char text[256];
29382938

29392939
if (!config) {
29402940
strcpy_s(text, MsgItems[First_menu_item + i].text.c_str());

code/hud/hudtarget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6092,7 +6092,7 @@ void HudGaugeWeaponEnergy::render(float /*frametime*/, bool config)
60926092
}
60936093
if(gr_screen.max_w_unscaled == 640) {
60946094
strcpy_s(shortened_name, weapon_name.c_str());
6095-
font::force_fit_string(shortened_name, NAME_LENGTH, fl2i(55 * scale), scale);
6095+
font::force_fit_string(shortened_name, NAME_LENGTH-1, fl2i(55 * scale), scale);
60966096
renderString(currentx, currenty, shortened_name, scale, config);
60976097
} else {
60986098
renderString(currentx, currenty, weapon_name.c_str(), scale, config);

code/menuui/barracks.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@
3838

3939
// stats defines
4040
//#define NUM_STAT_LINES (21 + MAX_SHIP_CLASSES) // Goober5000
41-
#define STAT_COLUMN1_W 40*2 // as we might use Unicode //ksotar
42-
#define STAT_COLUMN2_W 10
41+
#define STAT_COLUMN1_W 41*2 // as we might use Unicode //ksotar
42+
#define STAT_COLUMN2_W 11
4343

4444
static int Stat_column1_w[GR_NUM_RESOLUTIONS] =
4545
{

code/mission/missionlog.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ void mission_log_scrollback(int line_offset, int list_x, int list_y, int list_w,
794794

795795
char buf[256];
796796
strcpy_s(buf, Log_scrollback_vec[i].objective.text.get());
797-
font::force_fit_string(buf, 256, ACTION_X - OBJECT_X - 8);
797+
font::force_fit_string(buf, 255, ACTION_X - OBJECT_X - 8);
798798
gr_string(list_x + Log_scrollback_vec[i].objective.x, list_y + y, buf, GR_RESIZE_MENU);
799799

800800
// print the segments
@@ -814,7 +814,7 @@ void mission_log_scrollback(int line_offset, int list_x, int list_y, int list_w,
814814
gr_set_color_fast(this_color);
815815

816816
strcpy_s(buf, thisSeg.text.get());
817-
font::force_fit_string(buf, 256, list_w - thisSeg.x);
817+
font::force_fit_string(buf, 255, list_w - thisSeg.x);
818818
gr_string(list_x + thisSeg.x, list_y + seg_y, buf, GR_RESIZE_MENU);
819819
}
820820

code/missionui/missionbrief.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,7 +1251,7 @@ void brief_render(float frametime)
12511251

12521252
if (Game_mode & GM_MULTIPLAYER) {
12531253
char buf[256];
1254-
strncpy(buf, The_mission.name, 256);
1254+
strncpy(buf, The_mission.name, 255);
12551255
font::force_fit_string(buf, 255, Title_coords_multi[gr_screen.res][2]);
12561256
gr_string(Title_coords_multi[gr_screen.res][0], Title_coords_multi[gr_screen.res][1], buf, GR_RESIZE_MENU);
12571257
} else {

code/network/multiui.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,7 +1342,7 @@ void multi_join_display_games()
13421342
}
13431343

13441344
// make sure the string fits in the display area and draw it
1345-
font::force_fit_string(str,200,Mj_game_name_coords[gr_screen.res][MJ_W_COORD]);
1345+
font::force_fit_string(str, 199, Mj_game_name_coords[gr_screen.res][MJ_W_COORD]);
13461346
gr_string(Mj_game_name_coords[gr_screen.res][MJ_X_COORD],y_start,str,GR_RESIZE_MENU);
13471347

13481348
// display the ping time
@@ -4635,7 +4635,7 @@ void multi_create_list_do()
46354635
int idx;
46364636
int start_index,stop_index;
46374637
int line_height = gr_get_font_height() + 1;
4638-
char selected_name[255];
4638+
char selected_name[256];
46394639

46404640
// bail early if there aren't any selectable items
46414641
if(Multi_create_list_count == 0){
@@ -8357,7 +8357,7 @@ void multi_sync_post_close(bool API_Access)
83578357

83588358
void multi_sync_display_name(const char *name,int index,int np_index)
83598359
{
8360-
char fit[CALLSIGN_LEN];
8360+
char fit[CALLSIGN_LEN+1];
83618361
int line_height = gr_get_font_height() + 1;
83628362

83638363
// make sure the string actually fits
@@ -8433,7 +8433,7 @@ void multi_sync_display_status(const char *status,int index)
84338433

84348434
// make sure the string actually fits
84358435
strcpy_s(fit, status);
8436-
font::force_fit_string(fit, 250, Ms_status2_coords[gr_screen.res][MS_W_COORD] - 20);
8436+
font::force_fit_string(fit, 249, Ms_status2_coords[gr_screen.res][MS_W_COORD] - 20);
84378437
gr_set_color_fast(&Color_bright);
84388438
gr_string(Ms_status2_coords[gr_screen.res][MS_X_COORD], Ms_status2_coords[gr_screen.res][MS_Y_COORD] + (index * (gr_get_font_height() + 1)), fit, GR_RESIZE_MENU);
84398439
}

test/src/graphics/test_font.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,45 @@ TEST_F(FontTest, additional_font_ttf) {
3939

4040
font::close();
4141
}
42+
43+
TEST_F(FontTest, force_fit)
44+
{
45+
font::init();
46+
47+
{
48+
char str[] = "";
49+
int w = font::force_fit_string(str, std::string::npos, 80);
50+
ASSERT_EQ(w, 0);
51+
ASSERT_EQ(strlen(str), 0);
52+
}
53+
54+
{
55+
char str[] = "abcdefghijklmnopqrstuvwxyz";
56+
int w = font::force_fit_string(str, std::string::npos, 0);
57+
ASSERT_EQ(w, 0);
58+
ASSERT_EQ(strlen(str), 0);
59+
}
60+
61+
{
62+
char str[] = "abcdefghijklmnopqrstuvwxyz";
63+
int w = font::force_fit_string(str, std::string::npos, 80);
64+
ASSERT_LE(w, 80);
65+
ASSERT_EQ(strlen(str), 12);
66+
}
67+
68+
{
69+
char str[] = "abcdefghijklmnopqrstuvwxyz";
70+
int w = font::force_fit_string(str, 5, 300);
71+
ASSERT_LE(w, 300);
72+
ASSERT_EQ(strlen(str), 5);
73+
}
74+
75+
{
76+
char str[] = "abcdefghijklmnopqrstuvwxyz";
77+
int w = font::force_fit_string(str, std::string::npos, 300);
78+
ASSERT_LE(w, 300);
79+
ASSERT_EQ(strlen(str), 26);
80+
}
81+
82+
font::close();
83+
}

0 commit comments

Comments
 (0)