* Set a terminate() handler to ensure that we leave the BDB
environment cleanly even when an exception is thrown from a destructor. We still crash, but we don't take all other Nix processes with us.
This commit is contained in:
		
							parent
							
								
									644946feed
								
							
						
					
					
						commit
						cbfac2fdcc
					
				
					 6 changed files with 55 additions and 8 deletions
				
			
		|  | @ -7,6 +7,7 @@ | |||
| 
 | ||||
| #include <iostream> | ||||
| #include <cctype> | ||||
| #include <exception> | ||||
| 
 | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
|  | @ -81,6 +82,23 @@ struct RemoveTempRoots | |||
| void initDerivationsHelpers(); | ||||
| 
 | ||||
| 
 | ||||
| static void closeStore() | ||||
| { | ||||
|     try { | ||||
|         throw; | ||||
|     } catch (std::exception & e) { | ||||
|         printMsg(lvlError, | ||||
|             format("FATAL: unexpected exception (closing store and aborting): %1%") % e.what()); | ||||
|     } | ||||
|     try { | ||||
|         store.reset((StoreAPI *) 0); | ||||
|     } catch (...) { | ||||
|         ignoreException(); | ||||
|     } | ||||
|     abort(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Initialize and reorder arguments, then call the actual argument
 | ||||
|    processor. */ | ||||
| static void initAndRun(int argc, char * * argv) | ||||
|  | @ -195,6 +213,12 @@ static void initAndRun(int argc, char * * argv) | |||
|        exit. */ | ||||
|     RemoveTempRoots removeTempRoots; /* unused variable - don't remove */ | ||||
| 
 | ||||
|     /* Make sure that the database gets closed properly, even if
 | ||||
|        terminate() is called (which happens sometimes due to bugs in | ||||
|        destructor/exceptions interaction, but that needn't preclude a | ||||
|        clean shutdown of the database). */ | ||||
|     std::set_terminate(closeStore); | ||||
|      | ||||
|     run(remaining); | ||||
| 
 | ||||
|     /* Close the Nix database. */ | ||||
|  |  | |||
|  | @ -685,8 +685,8 @@ DerivationGoal::~DerivationGoal() | |||
|     try { | ||||
|         killChild(); | ||||
|         deleteTmpDir(false); | ||||
|     } catch (Error & e) { | ||||
|         printMsg(lvlError, format("error (ignored): %1%") % e.msg()); | ||||
|     } catch (...) { | ||||
|         ignoreException(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -161,7 +161,11 @@ LocalStore::LocalStore(bool reserveSpace) | |||
| LocalStore::~LocalStore() | ||||
| { | ||||
|     /* If the database isn't open, this is a NOP. */ | ||||
|     nixDB.close(); | ||||
|     try { | ||||
|         nixDB.close(); | ||||
|     } catch (...) { | ||||
|         ignoreException(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -148,8 +148,8 @@ RemoteStore::~RemoteStore() | |||
|         fdSocket.close(); | ||||
|         if (child != -1) | ||||
|             child.wait(true); | ||||
|     } catch (Error & e) { | ||||
|         printMsg(lvlError, format("error (ignored): %1%") % e.msg()); | ||||
|     } catch (...) { | ||||
|         ignoreException(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -444,7 +444,11 @@ void warnOnce(bool & haveWarned, const format & f) | |||
| 
 | ||||
| static void defaultWriteToStderr(const unsigned char * buf, size_t count) | ||||
| { | ||||
|     writeFull(STDERR_FILENO, buf, count); | ||||
|     try { | ||||
|         writeFull(STDERR_FILENO, buf, count); | ||||
|     } catch (SysError & e) { | ||||
|         /* ignore EPIPE etc. */ | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -545,8 +549,8 @@ AutoCloseFD::~AutoCloseFD() | |||
| { | ||||
|     try { | ||||
|         close(); | ||||
|     } catch (Error & e) { | ||||
|         printMsg(lvlError, format("error (ignored): %1%") % e.msg()); | ||||
|     } catch (...) { | ||||
|         ignoreException(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -969,4 +973,14 @@ bool string2Int(const string & s, int & n) | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| void ignoreException() | ||||
| { | ||||
|     try { | ||||
|         throw; | ||||
|     } catch (std::exception & e) { | ||||
|         printMsg(lvlError, format("error (ignored): %1%") % e.what()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|   | ||||
| } | ||||
|  |  | |||
|  | @ -280,6 +280,11 @@ string int2String(int n); | |||
| bool string2Int(const string & s, int & n); | ||||
| 
 | ||||
| 
 | ||||
| /* Exception handling in destructors: print an error message, then
 | ||||
|    ignore the exception. */ | ||||
| void ignoreException(); | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue