2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015,2016,2018,2019, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Declares common exception classes and macros for fatal error handling.
39 * The basic approach is the same as in boost::exception for storing additional
40 * context information to exceptions, but since that functionality is a very
41 * small and simple part of boost::exception, the code is duplicated here.
43 * \author Teemu Murtola <teemu.murtola@gmail.com>
45 * \ingroup module_utility
47 #ifndef GMX_UTILITY_EXCEPTIONS_H
48 #define GMX_UTILITY_EXCEPTIONS_H
56 #include <type_traits>
60 #include "gromacs/utility/basedefinitions.h"
61 #include "gromacs/utility/classhelpers.h"
62 #include "gromacs/utility/gmxassert.h"
64 #include "current_function.h"
73 //! Internal container type for storing a list of nested exceptions.
74 typedef std::vector<std::exception_ptr> NestedExceptionList;
78 * Base class for ExceptionInfo.
80 * This class only provides a way to store different ExceptionInfo objects in
81 * the same container. Actual access to the ExceptionInfo items is handled by
82 * downcasting, after looking up the correct item based on its type.
84 * \ingroup module_utility
89 virtual ~IExceptionInfo();
90 GMX_DEFAULT_CONSTRUCTORS(IExceptionInfo);
93 //! Smart pointer to manage IExceptionInfo ownership.
94 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer;
98 } // namespace internal
100 //! \addtogroup module_utility
104 * Stores additional context information for exceptions.
106 * \tparam Tag Tag type (typically, a forward-declared struct that is not
107 * defined anywhere) that makes all ExceptionInfo types unique, even if
108 * they have the same value type.
109 * \tparam T Type of value this object stores.
110 * Needs to be copy-constructible.
112 * Example of declaring a new info type that stores an integer:
114 typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo;
119 template<class Tag, typename T>
120 class ExceptionInfo : public internal::IExceptionInfo
123 //! The type of value stored in this object.
124 typedef T value_type;
126 //! Creates an info object from given value.
127 explicit ExceptionInfo(const T& value) : value_(value) {}
129 //! Returns the stored value.
130 const T& value() const { return value_; }
138 * Stores the location from which an exception was thrown.
142 //! Creates an object for storing the throw location.
143 ThrowLocation(const char* func, const char* file, int line) : func(func), file(file), line(line)
147 //! Function where the throw occurred.
149 //! File where the throw occurred.
151 //! Line number where the throw occurred.
155 //! Stores `errno` value that triggered the exception.
156 typedef ExceptionInfo<struct ExceptionInfoErrno_, int> ExceptionInfoErrno;
157 //! Stores the function name that returned the `errno` in ExceptionInfoErrno.
158 typedef ExceptionInfo<struct ExceptionInfoApiFunc_, const char*> ExceptionInfoApiFunction;
159 //! Stores the location where the exception was thrown.
160 typedef ExceptionInfo<struct ExceptionInfoLocation_, ThrowLocation> ExceptionInfoLocation;
163 * Provides information for Gromacs exception constructors.
165 * This class exists to implement common functionality for initializing all
166 * Gromacs exceptions without having extra code in each exception class.
167 * In simple cases, it can be implicitly constructed by passing a simple string
168 * to an exception constructor.
169 * If more complex initialization is necessary, it is possible to explicitly
170 * construct an object of this type and then call other methods to add
171 * information before actually creating the exception object.
174 * With the exception of the reason string, information added with this class
175 * is not currently accessible through any public API, except for calling
176 * printFatalErrorMessage(), formatExceptionMessageToString() or
177 * formatExceptionMessageToFile(). This is not implemented as there is not yet
178 * need for it, and it is not clear what would be the best alternative for the
179 * access. It should be possible to refactor the internal implementation to
180 * suit the needs of such external access without requiring changes in code
181 * that throws these exceptions.
183 * \ingroup module_utility
185 class ExceptionInitializer
189 * Creates an initialized with the given string as the reason.
191 * \param[in] reason Detailed reason for the exception.
192 * \throw std::bad_alloc if out of memory.
194 * This constructor is not explicit to allow constructing exceptions
195 * with a plain string argument given to the constructor without adding
196 * extra code to each exception class.
198 ExceptionInitializer(const char* reason) : reason_(reason) {}
199 //! \copydoc ExceptionInitializer(const char *)
200 ExceptionInitializer(const std::string& reason) : reason_(reason) {}
203 * Returns true if addCurrentExceptionAsNested() has been called.
205 * Provided for convenience for cases where exceptions will be added
206 * conditionally, and the caller wants to check whether any excetions
207 * were actually added.
209 bool hasNestedExceptions() const { return !nested_.empty(); }
211 * Adds the currently caught exception as a nested exception.
213 * May be called multiple times; all provided exceptions will be added
214 * in a list of nested exceptions.
216 * Must not be called outside a catch block.
218 void addCurrentExceptionAsNested() { nested_.push_back(std::current_exception()); }
220 * Adds the specified exception as a nested exception.
222 * May be called multiple times; all provided exceptions will be added
223 * in a list of nested exceptions.
225 * This is equivalent to throwing \p ex and calling
226 * addCurrentExceptionAsNested() in the catch block, but potentially
229 template<class Exception>
230 void addNested(const Exception& ex)
232 nested_.push_back(std::make_exception_ptr(ex));
237 internal::NestedExceptionList nested_;
239 friend class GromacsException;
243 * Base class for all exception objects in Gromacs.
247 class GromacsException : public std::exception
250 // Explicitly declared because some compiler/library combinations warn
251 // about missing noexcept otherwise.
252 ~GromacsException() noexcept override {}
254 GMX_DEFAULT_CONSTRUCTORS(GromacsException);
257 * Returns the reason string for the exception.
259 * The return value is the string that was passed to the constructor.
261 const char* what() const noexcept override;
263 * Returns the error code corresponding to the exception type.
265 virtual int errorCode() const = 0;
268 * Returns the value associated with given ExceptionInfo.
270 * \tparam InfoType ExceptionInfo type to get the value for.
271 * \returns Value set for `InfoType`, or `nullptr` if such info has not
276 template<class InfoType>
277 const typename InfoType::value_type* getInfo() const
279 const internal::IExceptionInfo* item = getInfo(typeid(InfoType));
282 GMX_ASSERT(dynamic_cast<const InfoType*>(item) != nullptr,
283 "Invalid exception info item found");
284 return &static_cast<const InfoType*>(item)->value();
290 * Associates extra information with the exception.
292 * \tparam Tag ExceptionInfo tag type.
293 * \tparam T ExceptionInfo value type.
294 * \param[in] item ExceptionInfo to associate.
295 * \throws std::bad_alloc if out of memory.
296 * \throws unspecified any exception thrown by `T` copy construction.
298 * If an item of this type is already associated, it is overwritten.
300 template<class Tag, typename T>
301 void setInfo(const ExceptionInfo<Tag, T>& item)
303 typedef ExceptionInfo<Tag, T> ItemType;
304 internal::ExceptionInfoPointer itemPtr(new ItemType(item));
305 setInfo(typeid(ItemType), std::move(itemPtr));
309 * Adds context information to this exception.
311 * \param[in] context Context string to add.
312 * \throws std::bad_alloc if out of memory.
314 * Typical use is to add additional information higher up in the call
315 * stack using this function in a catch block and the rethrow the
319 * The added information is currently not accessible through what(),
320 * nor through any other means except for calling
321 * printFatalErrorMessage(), formatExceptionMessageToString() or
322 * formatExceptionMessageToFile(). See ExceptionInitializer for more
325 void prependContext(const std::string& context);
329 * Creates an exception object with the provided initializer/reason.
331 * \param[in] details Initializer for the exception.
332 * \throws std::bad_alloc if out of memory.
334 explicit GromacsException(const ExceptionInitializer& details);
337 const internal::IExceptionInfo* getInfo(const std::type_index& index) const;
338 void setInfo(const std::type_index& index, internal::ExceptionInfoPointer&& item);
340 std::shared_ptr<internal::ExceptionData> data_;
344 * Associates extra information with an exception.
346 * \tparam Exception Exception type (must be derived from GromacsException).
347 * \tparam Tag ExceptionInfo tag.
348 * \tparam T ExceptionInfo value type.
349 * \param[in,out] ex Exception to associate the information to.
350 * \param[in] item Information to associate.
353 * The association is done with a templated non-member operator of exactly this
354 * form to make the simple syntax of GMX_THROW() possible. To support this,
355 * this operation needs to:
356 * - Allow setting information in a temporary to support
357 * `GMX_THROW(InvalidInputError(ex))`.
358 * - Return a copy of the same class it takes in. The compiler needs
359 * this information to throw the correct type of exception. This
360 * would be tedious to achieve with a member function (without a
361 * lot of code duplication). Generally, \c ex will be a temporary,
362 * copied twice and returned by value, which the compiler will
363 * typically elide away (and anyway performance is not important
364 * when throwing). We are not using the typical
365 * return-by-const-reference idiom for this operator so that
366 * tooling can reliably see that we are throwing by value.
367 * - Provide convenient syntax for adding multiple items. A non-member
368 * function that would require nested calls would look ugly for such cases.
370 * The reason for the enable_if is that this way, it does not conflict with
371 * other overloads of `operator<<` for ExceptionInfo objects, in case someone
372 * would like to declare those. But currently we do not have such overloads, so
373 * if the enable_if causes problems with some compilers, it can be removed.
375 template<class Exception, class Tag, class T>
376 inline std::enable_if_t<std::is_base_of<GromacsException, Exception>::value, Exception>
377 operator<<(Exception ex, const ExceptionInfo<Tag, T>& item)
384 * Exception class for file I/O errors.
388 class FileIOError : public GromacsException
392 * Creates an exception object with the provided initializer/reason.
394 * \param[in] details Initializer for the exception.
395 * \throws std::bad_alloc if out of memory.
397 * It is possible to call this constructor either with an explicit
398 * ExceptionInitializer object (useful for more complex cases), or
399 * a simple string if only a reason string needs to be provided.
401 explicit FileIOError(const ExceptionInitializer& details) : GromacsException(details) {}
403 int errorCode() const override;
407 * Exception class for user input errors.
409 * Derived classes should be used to indicate the nature of the error instead
410 * of throwing this class directly.
414 class UserInputError : public GromacsException
417 //! \copydoc FileIOError::FileIOError()
418 explicit UserInputError(const ExceptionInitializer& details) : GromacsException(details) {}
422 * Exception class for situations where user input cannot be parsed/understood.
426 class InvalidInputError : public UserInputError
429 //! \copydoc FileIOError::FileIOError()
430 explicit InvalidInputError(const ExceptionInitializer& details) : UserInputError(details) {}
432 int errorCode() const override;
436 * Exception class for situations where user input is inconsistent.
440 class InconsistentInputError : public UserInputError
443 //! \copydoc FileIOError::FileIOError()
444 explicit InconsistentInputError(const ExceptionInitializer& details) : UserInputError(details)
448 int errorCode() const override;
452 * Exception class when a specified tolerance cannot be achieved.
456 class ToleranceError : public GromacsException
460 * Creates an exception object with the provided initializer/reason.
462 * \param[in] details Initializer for the exception.
463 * \throws std::bad_alloc if out of memory.
465 * It is possible to call this constructor either with an explicit
466 * ExceptionInitializer object (useful for more complex cases), or
467 * a simple string if only a reason string needs to be provided.
469 explicit ToleranceError(const ExceptionInitializer& details) : GromacsException(details) {}
471 int errorCode() const override;
475 * Exception class for simulation instabilities.
479 class SimulationInstabilityError : public GromacsException
482 //! \copydoc FileIOError::FileIOError()
483 explicit SimulationInstabilityError(const ExceptionInitializer& details) :
484 GromacsException(details)
488 int errorCode() const override;
492 * Exception class for internal errors.
496 class InternalError : public GromacsException
499 //! \copydoc FileIOError::FileIOError()
500 explicit InternalError(const ExceptionInitializer& details) : GromacsException(details) {}
502 int errorCode() const override;
506 * Exception class for incorrect use of an API.
510 class APIError : public GromacsException
513 //! \copydoc FileIOError::FileIOError()
514 explicit APIError(const ExceptionInitializer& details) : GromacsException(details) {}
516 int errorCode() const override;
520 * Exception class for out-of-range values or indices
524 class RangeError : public GromacsException
527 //! \copydoc FileIOError::FileIOError()
528 explicit RangeError(const ExceptionInitializer& details) : GromacsException(details) {}
530 int errorCode() const override;
534 * Exception class for use of an unimplemented feature.
538 class NotImplementedError : public APIError
541 //! \copydoc FileIOError::FileIOError()
542 explicit NotImplementedError(const ExceptionInitializer& details) : APIError(details) {}
544 int errorCode() const override;
547 /*! \brief Exception class for use when ensuring that MPI ranks to throw
548 * in a coordinated fashion.
550 * Generally all ranks that can throw would need to check for whether
551 * an exception has been caught, communicate whether any rank caught,
552 * then all throw one of these, with either a string that describes
553 * any exception caught on that rank, or a generic string.
557 class ParallelConsistencyError : public APIError
560 //! \copydoc FileIOError::FileIOError()
561 explicit ParallelConsistencyError(const ExceptionInitializer& details) : APIError(details) {}
563 int errorCode() const override;
567 * Macro for throwing an exception.
569 * \param[in] e Exception object to throw.
571 * Using this macro instead of \c throw directly makes it possible to uniformly
572 * attach information into the exception objects.
573 * \p e should evaluate to an instance of an object derived from
580 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
584 #define GMX_THROW(e) \
585 throw(e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
588 * Macro for throwing an exception based on errno.
590 * \param[in] e Exception object to throw.
591 * \param[in] syscall Name of the syscall that returned the error.
592 * \param[in] err errno value returned by the syscall.
594 * This macro provides a convenience interface for throwing an exception to
595 * report an error based on a errno value. In addition to adding the necessary
596 * information to the exception object, the macro also ensures that \p errno is
597 * evaluated before, e.g., the constructor of \p e may call other functions
598 * that could overwrite the errno value.
599 * \p e should evaluate to an instance of an object derived from
602 * Typical usage (note that gmx::File wraps this particular case):
604 FILE *fp = fopen("filename.txt", "r");
607 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
611 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
614 int stored_errno_ = (err); \
615 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
616 << gmx::ExceptionInfoApiFunction(syscall)); \
618 // TODO: Add an equivalent macro for Windows GetLastError
621 * Formats a standard fatal error message for reporting an exception.
623 * \param[in] fp %File to format the message to.
624 * \param[in] ex Exception to format.
626 * Does not throw. If memory allocation fails or some other error occurs
627 * while formatting the error, tries to print a reasonable alternative message.
629 * Normal usage in Gromacs command-line programs is like this:
631 int main(int argc, char *argv[])
633 gmx::init(&argc, &argv);
636 // The actual code for the program
639 catch (const std::exception &ex)
641 gmx::printFatalErrorMessage(stderr, ex);
642 return gmx::processExceptionAtExit(ex);
647 void printFatalErrorMessage(FILE* fp, const std::exception& ex);
649 * Formats an error message for reporting an exception.
651 * \param[in] ex Exception to format.
652 * \returns Formatted string containing details of \p ex.
653 * \throws std::bad_alloc if out of memory.
655 std::string formatExceptionMessageToString(const std::exception& ex);
657 * Formats an error message for reporting an exception.
659 * \param fp %File to write the message to.
660 * \param[in] ex Exception to format.
661 * \throws std::bad_alloc if out of memory.
663 void formatExceptionMessageToFile(FILE* fp, const std::exception& ex);
665 * Formats an error message for reporting an exception.
667 * \param writer Writer to use for writing the message.
668 * \param[in] ex Exception to format.
669 * \throws std::bad_alloc if out of memory.
671 void formatExceptionMessageToWriter(TextWriter* writer, const std::exception& ex);
673 * Handles an exception that is causing the program to terminate.
675 * \param[in] ex Exception that is the cause for terminating the program.
676 * \returns Return code to return from main().
678 * This method should be called as the last thing before terminating the
679 * program because of an exception. It exists to terminate the program as
680 * gracefully as possible in the case of MPI processing (but the current
681 * implementation always calls MPI_Abort()).
683 * See printFatalErrorMessage() for example usage.
687 int processExceptionAtExit(const std::exception& ex);
690 * Helper function for terminating the program on an exception.
692 * \param[in] ex Exception that is the cause for terminating the program.
694 * Does not throw, and does not return.
696 [[noreturn]] void processExceptionAsFatalError(const std::exception& ex);
699 * Macro for catching exceptions at C++ -> C boundary.
701 * This macro is intended for uniform handling of exceptions when C++ code is
702 * called from C code within Gromacs. Since most existing code is written
703 * using the assumption that fatal errors terminate the program, this macro
704 * implements this behavior for exceptions. It should only be used in cases
705 * where the error cannot be propagated upwards using return values or such.
707 * Having this as a macro instead of having the same code in each place makes
708 * it easy to 1) find all such locations in the code, and 2) change the exact
709 * behavior if needed.
717 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
720 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
721 catch (const std::exception& ex) { ::gmx::processExceptionAsFatalError(ex); }