Skip to content

Commit b5a8273

Browse files
committed
Fix a case of static initialization order debacle
When descent3 is built with g++ -flto=auto, there is a crash at startup: ``` Program received signal SIGSEGV, Segmentation fault. 0x00005555557b3b20 in pilot::initialize ( this=this@entry=0x555555fbd480 <Current_pilot>) at Descent3/pilot_class.cpp:208 208 game_window_w = Video_res_list[Current_video_resolution_id].width; Missing separate debuginfos, use: zypper install libcpp-httplib0_20-debuginfo-0.20.1-2.1.x86_64 libSDL3-0-debuginfo-3.2.16-1.1.x86_64 libzstd1-x86-64-v3-debuginfo-1.5.7-3.1.x86_64 (gdb) p Current_video_resolution_id $1 = 0 (gdb) p Video_res_list $2 = std::vector of length 0, capacity 0 (gdb) bt f0 pilot::initialize (this=this@entry=0x555555fbd480 <Current_pilot>) at Descent3/pilot_class.cpp:208 f1 pilot::pilot (this=<optimized out>, this=<optimized out>) at Descent3/pilot_class.cpp:177 f2 _sub_I_65535_0.0 () f3 call_init (argc=1, argv=0x7fffffffdb68, env=<optimized out>) at ../csu/libc-start.c:145 f4 __libc_start_main_impl f5 _start () at ../sysdeps/x86_64/start.S:115 ``` When ASAN/UBSAN is enabled in conjunction with LTO: ``` /usr/include/c++/14/bits/stl_vector.h:1144:34: runtime error: reference binding to null pointer of type 'struct value_type' Descent3/pilot_class.cpp:208:63: runtime error: member access within null pointer of type 'struct value_type' AddressSanitizer:DEADLYSIGNAL ================================================================= ==58724==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 ==58724==The signal is caused by a READ memory access. ==58724==Hint: address points to the zero page. f0 pilot::initialize() Descent3/pilot_class.cpp:208 f1 pilot::pilot() Descent3/pilot_class.cpp:177 f2 _sub_I_65535_0.0 (b/build/Descent3+0x52ece3) f3 call_init ../csu/libc-start.c:145 f4 __libc_start_main_impl ../csu/libc-start.c:347 f5 _start ../sysdeps/x86_64/start.S:115 ``` ``_sub_I_65535_0.0`` is indicative of a global constructor, so we are looking at a case of Static Initialization Order Fiasco whereby ``pilot::initialize`` runs before ``Video_res_list`` gets initialized. Static variables declared in functions are initialized on first use, which can help steer global initialization short of placing the global state in a class instance of its own. Fixes: 40c7f0d
1 parent e684a16 commit b5a8273

File tree

6 files changed

+50
-46
lines changed

6 files changed

+50
-46
lines changed

Descent3/config.cpp

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -314,31 +314,23 @@
314314

315315
#define STAT_SCORE STAT_TIMER
316316

317-
// This list is only used if `ConfigureDisplayResolutions` fails
318-
std::vector<tVideoResolution> Video_res_list = {{512, 384},
319-
{640, 480},
320-
{800, 600},
321-
{960, 720},
322-
{1024, 768},
323-
{1280, 960},
324-
{1600, 1200},
325-
// 16:9
326-
{1280, 720},
327-
{1366, 768},
328-
{1368, 768},
329-
{1680, 1050},
330-
{1920, 1080},
331-
{2560, 1440},
332-
{3840, 2160},
333-
// 16:10
334-
{1280, 800},
335-
{1920, 1200},
336-
{2560, 1600},
337-
// Ultrawide
338-
{2560, 1080},
339-
{2880, 1200},
340-
{3440, 1440},
341-
{3840, 1600}};
317+
std::vector<tVideoResolution> &Video_res_list()
318+
{
319+
// This list is only used if `ConfigureDisplayResolutions` fails
320+
static std::vector<tVideoResolution> list = {
321+
// 4:3
322+
{512, 384}, {640, 480}, {800, 600}, {960, 720}, {1024, 768},
323+
{1280, 960}, {1600, 1200},
324+
// 16:9
325+
{1280, 720}, {1366, 768}, {1368, 768}, {1680, 1050},
326+
{1920, 1080}, {2560, 1440}, {3840, 2160},
327+
// 16:10
328+
{1280, 800}, {1920, 1200}, {2560, 1600},
329+
// Ultrawide
330+
{2560, 1080}, {2880, 1200}, {3440, 1440}, {3840, 1600}
331+
};
332+
return list;
333+
}
342334

343335
int Default_resolution_id = 7; // 1280x720 in the default list
344336
int Current_video_resolution_id = Default_resolution_id;
@@ -417,15 +409,16 @@ void ConfigureDisplayResolutions() {
417409
if (resolutions_vec.empty()) {
418410
return;
419411
}
420-
Video_res_list = std::move(resolutions_vec);
412+
auto &vres = Video_res_list();
413+
vres = std::move(resolutions_vec);
421414
SDL_free(displays);
422415

423416
// Find the index of the current screen resolution in the list
424-
auto current_res_id = std::find(Video_res_list.begin(), Video_res_list.end(), current_resolution);
425-
if (current_res_id != Video_res_list.end()) {
426-
Default_resolution_id = static_cast<int>(current_res_id - Video_res_list.begin());
417+
auto current_res_id = std::find(vres.cbegin(), vres.cend(), current_resolution);
418+
if (current_res_id != vres.end()) {
419+
Default_resolution_id = static_cast<int>(current_res_id - vres.begin());
427420
} else {
428-
Default_resolution_id = Video_res_list.size() - 1; // default to the highest supported resolution
421+
Default_resolution_id = vres.size() - 1; // default to the highest supported resolution
429422
}
430423

431424
int tmp;
@@ -434,8 +427,8 @@ void ConfigureDisplayResolutions() {
434427
Current_video_resolution_id = Default_resolution_id;
435428
}
436429

437-
LOG_DEBUG << "Resolution configured to w=" << Video_res_list[Current_video_resolution_id].width
438-
<< "h=" << Video_res_list[Current_video_resolution_id].height << " (id " << Current_video_resolution_id
430+
LOG_DEBUG << "Resolution configured to w=" << vres[Current_video_resolution_id].width
431+
<< "h=" << vres[Current_video_resolution_id].height << " (id " << Current_video_resolution_id
439432
<< ")";
440433
}
441434

@@ -782,7 +775,8 @@ struct video_menu {
782775

783776
// video resolution
784777
sheet->NewGroup(TXT_RESOLUTION, 0, 0);
785-
std::string res = Video_res_list[Current_video_resolution_id].getName();
778+
auto &vres = Video_res_list();
779+
std::string res = vres[Current_video_resolution_id].getName();
786780
auto alloc_size = std::max(res.size() + 1, static_cast<size_t>(15));
787781
resolution_string = sheet->AddChangeableText(alloc_size);
788782
snprintf(resolution_string, alloc_size, res.c_str());
@@ -856,8 +850,9 @@ struct video_menu {
856850
Render_preferred_state.bit_depth = Render_preferred_bitdepth;
857851
rend_SetPreferredState(&Render_preferred_state, true);
858852

859-
int temp_w = Video_res_list[Current_video_resolution_id].width;
860-
int temp_h = Video_res_list[Current_video_resolution_id].height;
853+
auto &vres = Video_res_list();
854+
int temp_w = vres[Current_video_resolution_id].width;
855+
int temp_h = vres[Current_video_resolution_id].height;
861856
Current_pilot.set_hud_data(NULL, NULL, NULL, &temp_w, &temp_h);
862857
}
863858

@@ -886,7 +881,8 @@ struct video_menu {
886881
select_sheet->AddButton(TXT_OK, UID_OK);
887882
select_sheet->AddButton(TXT_CANCEL, UID_CANCEL);
888883

889-
for (auto &resolution : Video_res_list) {
884+
auto &vres = Video_res_list();
885+
for (auto &resolution : vres) {
890886
resolution_list->AddItem(resolution.getName().c_str());
891887
}
892888

@@ -901,10 +897,10 @@ struct video_menu {
901897

902898
if (res == UID_OK) {
903899
int newindex = resolution_list->GetCurrentIndex();
904-
if (static_cast<size_t>(newindex) < Video_res_list.size() && Current_video_resolution_id != newindex) {
900+
if (static_cast<size_t>(newindex) < vres.size() && Current_video_resolution_id != newindex) {
905901
resolution_changed = true;
906902
Current_video_resolution_id = newindex;
907-
std::string res = Video_res_list[Current_video_resolution_id].getName();
903+
std::string res = vres[Current_video_resolution_id].getName();
908904
snprintf(resolution_string, res.size() + 1, res.c_str());
909905
}
910906
}

Descent3/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ struct tVideoResolution
155155
}
156156
};
157157

158-
extern std::vector<tVideoResolution> Video_res_list;
158+
extern std::vector<tVideoResolution> &Video_res_list();
159159
extern int Default_resolution_id;
160160
extern int Current_video_resolution_id;
161161
extern int Display_id;

Descent3/game.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,8 +937,8 @@ void SetScreenMode(int sm, bool force_res_change) {
937937
int scr_width, scr_height, scr_bitdepth;
938938

939939
if (sm == SM_GAME) {
940-
scr_width = Video_res_list[Current_video_resolution_id].width;
941-
scr_height = Video_res_list[Current_video_resolution_id].height;
940+
scr_width = Video_res_list()[Current_video_resolution_id].width;
941+
scr_height = Video_res_list()[Current_video_resolution_id].height;
942942
scr_bitdepth = Render_preferred_bitdepth;
943943
} else {
944944
scr_width = FIXED_SCREEN_WIDTH;

Descent3/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ void LoadGameSettings() {
13051305
Database->read("Specmapping", &Detail_settings.Specular_lighting);
13061306
Database->read("RS_bitdepth", &Render_preferred_bitdepth, sizeof(Render_preferred_bitdepth));
13071307
Database->read_int("RS_resolution", &tempint);
1308-
if (tempint >= 0 && tempint < std::size(Video_res_list))
1308+
if (tempint >= 0 && tempint < Video_res_list().size())
13091309
Current_video_resolution_id = tempint;
13101310
else
13111311
LOG_WARNING << "Game settings contain a display resolution index that is out of bounds. Starting with default resolution.";

Descent3/pilot_class.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,8 +205,15 @@ void pilot::initialize(void) {
205205
hud_mode = (uint8_t)HUD_COCKPIT;
206206
hud_stat = 0;
207207
hud_graphical_stat = STAT_STANDARD;
208-
game_window_w = Video_res_list[Current_video_resolution_id].width;
209-
game_window_h = Video_res_list[Current_video_resolution_id].height;
208+
auto &vres = Video_res_list();
209+
if (Current_video_resolution_id >= 0 &&
210+
static_cast<size_t>(Current_video_resolution_id) < vres.size()) {
211+
game_window_w = vres[Current_video_resolution_id].width;
212+
game_window_h = vres[Current_video_resolution_id].height;
213+
} else {
214+
game_window_w = 0;
215+
game_window_h = 0;
216+
}
210217
num_missions_flown = 0;
211218
mission_data = NULL;
212219
mouselook_control = false;

renderer/HardwareOpenGL.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,9 @@ void opengl_SetDefaults() {
348348
extern renderer_preferred_state Render_preferred_state;
349349

350350
int opengl_Setup(oeApplication *app, const int *width, const int *height) {
351-
int winw = Video_res_list[Current_video_resolution_id].width;
352-
int winh = Video_res_list[Current_video_resolution_id].height;
351+
auto &vres = Video_res_list();
352+
int winw = vres[Current_video_resolution_id].width;
353+
int winh = vres[Current_video_resolution_id].height;
353354

354355
SDL_ClearError();
355356
if (!SDL_WasInit(SDL_INIT_VIDEO)) {

0 commit comments

Comments
 (0)