aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-04-04 17:31:01 +0200
committereldritch horrors <pennae@lix.systems>2024-04-05 20:13:02 +0000
commit6c777476c9e97abfc5232f0707985caf6df2baea (patch)
tree84209c1b850eb85d4fa575fff9da3345b4ee4ff5 /src/libutil
parent5081109592778d6026669db831758b61e5b43c33 (diff)
libutil: guard Finally against invalid exception throws
throwing exceptions is fine, but throwing exceptions during exception handling is hard enough to do correctly that we should just forbid it entirely out of an overabundance of caution. in cases where terminate is the correct answer the users of Finally must call it manually now. Change-Id: Ia51a2cb4a0638500550bfabc89cf01a6d8098983
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/finally.hh25
1 files changed, 24 insertions, 1 deletions
diff --git a/src/libutil/finally.hh b/src/libutil/finally.hh
index f2293e5d4..cbfd6195b 100644
--- a/src/libutil/finally.hh
+++ b/src/libutil/finally.hh
@@ -1,6 +1,9 @@
#pragma once
///@file
+#include <cassert>
+#include <exception>
+
/**
* A trivial class to run a function at the end of a scope.
*/
@@ -19,5 +22,25 @@ public:
Finally(Finally &&other) : fun(std::move(other.fun)) {
other.movedFrom = true;
}
- ~Finally() noexcept(false) { if (!movedFrom) fun(); }
+ ~Finally() noexcept(false)
+ {
+ try {
+ if (!movedFrom)
+ fun();
+ } catch (...) {
+ // finally may only throw an exception if exception handling is not already
+ // in progress. if handling *is* in progress we have to return cleanly here
+ // but are still prohibited from doing so since eating the exception would,
+ // in almost all cases, mess up error handling even more. the only good way
+ // to handle this is to abort entirely and leave a message, so we'll assert
+ // (and rethrow anyway, just as a defense against possible NASSERT builds.)
+ if (std::uncaught_exceptions()) {
+ assert(false &&
+ "Finally function threw an exception during exception handling. "
+ "this is not what you want, please use some other methods (like "
+ "std::promise or async) instead.");
+ }
+ throw;
+ }
+ }
};