From cbfac2fdccc83b04d9c2027e9e21070d4ac7c7e5 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 1 May 2007 15:16:17 +0000 Subject: [PATCH] * 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. --- src/libmain/shared.cc | 24 ++++++++++++++++++++++++ src/libstore/build.cc | 4 ++-- src/libstore/local-store.cc | 6 +++++- src/libstore/remote-store.cc | 4 ++-- src/libutil/util.cc | 20 +++++++++++++++++--- src/libutil/util.hh | 5 +++++ 6 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 568c975c2..ebdbeb11e 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) @@ -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. */ diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 7009876f1..5c8b31cf6 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -685,8 +685,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 7b7efc84b..cd8bc1a33 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -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(); + } } diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index 1aab90d38..449a4c448 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -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(); } } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index ae5af2492..d61b35bdf 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -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(); } } @@ -968,5 +972,15 @@ bool string2Int(const string & s, int & n) return str && str.get() == EOF; } + +void ignoreException() +{ + try { + throw; + } catch (std::exception & e) { + printMsg(lvlError, format("error (ignored): %1%") % e.what()); + } +} + } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 4d284ccfd..63389867f 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -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(); + + }