diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 9d149a8a1..b6c388afd 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -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) @@ -206,6 +224,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. */ diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 3375fee59..ace5e473d 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -697,8 +697,8 @@ DerivationGoal::~DerivationGoal() try { killChild(); deleteTmpDir(false); - } catch (Error & e) { - printMsg(lvlError, format("error (ignored): %1%") % e.msg()); + } catch (...) { + ignoreException(); } } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index a902a19df..0028c88d3 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -274,7 +274,11 @@ LocalStore::LocalStore(bool reserveSpace) LocalStore::~LocalStore() { /* If the database isn't open, this is a NOP. */ - nixDB.close(); + try { + nixDB.close(); + } catch (...) { + ignoreException(); + } } diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 2c2478e03..cfad41162 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -149,8 +149,8 @@ RemoteStore::~RemoteStore() fdSocket.close(); if (child != -1) child.wait(true); - } catch (Error & e) { - printMsg(lvlError, format("error (ignored): %1%") % e.msg()); + } catch (...) { + ignoreException(); } } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 07da64a23..effb0174b 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -446,7 +446,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. */ + } } @@ -548,8 +552,8 @@ AutoCloseFD::~AutoCloseFD() { try { close(); - } catch (Error & e) { - printMsg(lvlError, format("error (ignored): %1%") % e.msg()); + } catch (...) { + ignoreException(); } } @@ -1046,6 +1050,15 @@ string unsignedInt2String(unsigned int n) return str.str(); } +void ignoreException() +{ + try { + throw; + } catch (std::exception & e) { + printMsg(lvlError, format("error (ignored): %1%") % e.what()); + } +} + bool string2UnsignedInt(const string & s, unsigned int & n) { std::istringstream str(s); diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 6073eb465..c0dbbeb5b 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -336,6 +336,10 @@ void removeSymlink(const string & path); void ensureStateDir(const Path & statePath, const string & user, const string & group, const string & chmod); +/* Exception handling in destructors: print an error message, then + ignore the exception. */ +void ignoreException(); + } #endif /* !__UTIL_H */