(svn r14773) -Fix-ish[FS#2469]: attach a signal handler during loading savegames to catch any crashes due to broken savegames/missing NewGRFs and tell the user about that instead of "just" crashing without explanation.

This commit is contained in:
rubidium 2008-12-30 15:14:23 +00:00
parent 3c6add5293
commit 32583bd405
2 changed files with 61 additions and 4 deletions

View File

@ -84,6 +84,7 @@
#include "water.h"
#include <stdarg.h>
#include <signal.h>
#include "table/strings.h"
@ -1309,8 +1310,51 @@ static bool InitializeWindowsAndCaches()
return true;
}
/**
* Signal handler used to give a user a more useful report for crashes during
* the savegame loading process; especially when there's problems with the
* NewGRFs that are required by the savegame.
* @param unused well... unused
*/
void CDECL HandleSavegameLoadCrash(int unused)
{
char buffer[8192];
char *p = buffer;
p += seprintf(p, lastof(buffer),
"Loading your savegame caused OpenTTD to crash.\n"
"This is most likely caused by a missing NewGRF or a NewGRF that has been\n"
"loaded as replacement for a missing NewGRF. OpenTTD cannot easily\n"
"determine whether a replacement NewGRF is of a newer or older version.\n"
"It will load a NewGRF with the same GRF ID as the missing NewGRF. This\n"
"means that if the author makes incompatible NewGRFs with the same GRF ID\n"
"OpenTTD cannot magically do the right thing. In most cases OpenTTD will\n"
"load the savegame and not crash, but this is an exception.\n"
"Please load the savegame with the appropriate NewGRFs. When loading a\n"
"savegame still crashes when all NewGRFs are found you should file a\n"
"bug report. The missing NewGRFs are:\n");
for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
if (HasBit(c->flags, GCF_COMPATIBLE)) {
char buf[40];
md5sumToString(buf, lastof(buf), c->md5sum);
p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s. Tried another NewGRF with same GRF ID\n", BSWAP32(c->grfid), c->filename, buf);
}
if (c->status == GCS_NOT_FOUND) {
char buf[40];
md5sumToString(buf, lastof(buf), c->md5sum);
p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s\n", BSWAP32(c->grfid), c->filename, buf);
}
}
ShowInfo(buffer);
}
bool AfterLoadGame()
{
typedef void (CDECL *SignalHandlerPointer)(int);
SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash);
SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash);
TileIndex map_size = MapSize();
Company *c;
@ -1421,6 +1465,9 @@ bool AfterLoadGame()
GRFListCompatibility gcf_res = IsGoodGRFConfigList();
if (_networking && gcf_res != GLC_ALL_GOOD) {
SetSaveLoadError(STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH);
/* Restore the signals */
signal(SIGSEGV, prev_segfault);
signal(SIGABRT, prev_abort);
return false;
}
@ -1468,6 +1515,9 @@ bool AfterLoadGame()
/* make sure there is a town in the game */
if (_game_mode == GM_NORMAL && !ClosestTownFromTile(0, UINT_MAX)) {
SetSaveLoadError(STR_NO_TOWN_IN_SCENARIO);
/* Restore the signals */
signal(SIGSEGV, prev_segfault);
signal(SIGABRT, prev_abort);
return false;
}
@ -1529,6 +1579,9 @@ bool AfterLoadGame()
st = STATION_BUS;
SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET);
} else {
/* Restore the signals */
signal(SIGSEGV, prev_segfault);
signal(SIGABRT, prev_abort);
return false;
}
SB(_m[t].m6, 3, 3, st);
@ -2647,7 +2700,11 @@ bool AfterLoadGame()
GamelogPrintDebug(1);
return InitializeWindowsAndCaches();
bool ret = InitializeWindowsAndCaches();
/* Restore the signals */
signal(SIGSEGV, prev_segfault);
signal(SIGABRT, prev_abort);
return ret;
}
/** Reload all NewGRF files during a running game. This is a cut-down

View File

@ -934,9 +934,9 @@ void ShowInfo(const char *str)
} else {
bool old;
#if defined(UNICODE)
/* We need to put the text in a seperate buffer because the default
* buffer in MB_TO_WIDE might not be large enough (512 chars) */
wchar_t help_msgW[4096];
/* We need to put the text in a seperate buffer because the default
* buffer in MB_TO_WIDE might not be large enough (512 chars) */
wchar_t help_msgW[8192];
#endif
ReleaseCapture();
_left_button_clicked =_left_button_down = false;