changeset 11948:ad1ecf6b26e4 draft

(svn r16351) -Fix (r14773): signal handler could end in endless loop
author smatz <smatz@openttd.org>
date Mon, 18 May 2009 12:01:13 +0000
parents 5af9f5ff05d3
children c89301974eb8
files src/saveload/afterload.cpp
diffstat 1 files changed, 37 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -235,14 +235,41 @@
 	return true;
 }
 
+typedef void (CDECL *SignalHandlerPointer)(int);
+static SignalHandlerPointer _prev_segfault = NULL;
+static SignalHandlerPointer _prev_abort = NULL;
+
+static void CDECL HandleSavegameLoadCrash(int signum);
+
+/**
+ * Replaces signal handlers of SIGSEGV and SIGABRT
+ * and stores pointers to original handlers in memory.
+ */
+static void SetSignalHandlers()
+{
+	_prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash);
+	_prev_abort = signal(SIGABRT, HandleSavegameLoadCrash);
+}
+
+/**
+ * Resets signal handlers back to original handlers.
+ */
+static void ResetSignalHandlers()
+{
+	signal(SIGSEGV, _prev_segfault);
+	signal(SIGABRT, _prev_abort);
+}
+
 /**
  * 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
+ * @param signum received signal
  */
-void CDECL HandleSavegameLoadCrash(int unused)
+static void CDECL HandleSavegameLoadCrash(int signum)
 {
+	ResetSignalHandlers();
+
 	char buffer[8192];
 	char *p = buffer;
 	p += seprintf(p, lastof(buffer),
@@ -272,6 +299,9 @@
 	}
 
 	ShowInfo(buffer);
+
+	SignalHandlerPointer call = signum == SIGSEGV ? _prev_segfault : _prev_abort;
+	if (call != NULL) call(signum);
 }
 
 /**
@@ -322,9 +352,7 @@
 
 bool AfterLoadGame()
 {
-	typedef void (CDECL *SignalHandlerPointer)(int);
-	SignalHandlerPointer prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash);
-	SignalHandlerPointer prev_abort = signal(SIGABRT, HandleSavegameLoadCrash);
+	SetSignalHandlers();
 
 	TileIndex map_size = MapSize();
 	Company *c;
@@ -437,8 +465,7 @@
 	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);
+		ResetSignalHandlers();
 		return false;
 	}
 
@@ -490,8 +517,7 @@
 	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);
+		ResetSignalHandlers();
 		return false;
 	}
 
@@ -554,8 +580,7 @@
 						SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET);
 					} else {
 						/* Restore the signals */
-						signal(SIGSEGV, prev_segfault);
-						signal(SIGABRT, prev_abort);
+						ResetSignalHandlers();
 						return false;
 					}
 					SB(_m[t].m6, 3, 3, st);
@@ -1813,8 +1838,7 @@
 
 	bool ret = InitializeWindowsAndCaches();
 	/* Restore the signals */
-	signal(SIGSEGV, prev_segfault);
-	signal(SIGABRT, prev_abort);
+	ResetSignalHandlers();
 	return ret;
 }