Skip to content

Commit

Permalink
libutil: guard Finally against invalid exception throws
Browse files Browse the repository at this point in the history
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.

Source: https://git.lix.systems/lix-project/lix/commit/6c777476c9e97abfc5232f0707985caf6df2baea
  • Loading branch information
eldritch horrors authored and Mic92 committed Jun 5, 2024
1 parent edd445f commit e291087
Showing 1 changed file with 23 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/libutil/finally.hh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
///@file

#include <utility>
#include <cassert>
#include <exception>

/**
* A trivial class to run a function at the end of a scope.
Expand All @@ -21,5 +23,25 @@ public:
Finally(Finally &&other) : fun(std::move(other.fun)) {
other.movedFrom = true;
}
~Finally() { 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;
}
}
};

0 comments on commit e291087

Please sign in to comment.