2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015 by the GROMACS development team.
5 * Copyright (c) 2016,2018,2019,2020, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * Declares common exception classes and macros for fatal error handling.
40 * The basic approach is the same as in boost::exception for storing additional
41 * context information to exceptions, but since that functionality is a very
42 * small and simple part of boost::exception, the code is duplicated here.
44 * \author Teemu Murtola <teemu.murtola@gmail.com>
46 * \ingroup module_utility
48 #ifndef GMX_UTILITY_EXCEPTIONS_H
49 #define GMX_UTILITY_EXCEPTIONS_H
57 #include <type_traits>
61 #include "gromacs/utility/basedefinitions.h"
62 #include "gromacs/utility/gmxassert.h"
71 //! Internal container type for storing a list of nested exceptions.
72 typedef std::vector<std::exception_ptr> NestedExceptionList;
76 * Base class for ExceptionInfo.
78 * This class only provides a way to store different ExceptionInfo objects in
79 * the same container. Actual access to the ExceptionInfo items is handled by
80 * downcasting, after looking up the correct item based on its type.
82 * \ingroup module_utility
87 virtual ~IExceptionInfo();
88 IExceptionInfo() = default;
89 IExceptionInfo(const IExceptionInfo&) = default;
90 IExceptionInfo(IExceptionInfo&&) noexcept = default;
91 IExceptionInfo& operator=(const IExceptionInfo&) = default;
92 IExceptionInfo& operator=(IExceptionInfo&&) noexcept = default;
95 //! Smart pointer to manage IExceptionInfo ownership.
96 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer;
100 } // namespace internal
102 //! \addtogroup module_utility
106 * Stores additional context information for exceptions.
108 * \tparam Tag Tag type (typically, a forward-declared struct that is not
109 * defined anywhere) that makes all ExceptionInfo types unique, even if
110 * they have the same value type.
111 * \tparam T Type of value this object stores.
112 * Needs to be copy-constructible.
114 * Example of declaring a new info type that stores an integer:
116 typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo;
121 template<class Tag, typename T>
122 class ExceptionInfo : public internal::IExceptionInfo
125 //! The type of value stored in this object.
126 typedef T value_type;
128 //! Creates an info object from given value.
129 explicit ExceptionInfo(const T& value) : value_(value) {}
131 //! Returns the stored value.
132 const T& value() const { return value_; }
140 * Stores the location from which an exception was thrown.
144 //! Creates an object for storing the throw location.
145 ThrowLocation(const char* func, const char* file, int line) : func(func), file(file), line(line)
149 //! Function where the throw occurred.
151 //! File where the throw occurred.
153 //! Line number where the throw occurred.
157 //! Stores `errno` value that triggered the exception.
158 typedef ExceptionInfo<struct ExceptionInfoErrno_, int> ExceptionInfoErrno;
159 //! Stores the function name that returned the `errno` in ExceptionInfoErrno.
160 typedef ExceptionInfo<struct ExceptionInfoApiFunc_, const char*> ExceptionInfoApiFunction;
161 //! Stores the location where the exception was thrown.
162 typedef ExceptionInfo<struct ExceptionInfoLocation_, ThrowLocation> ExceptionInfoLocation;
165 * Provides information for Gromacs exception constructors.
167 * This class exists to implement common functionality for initializing all
168 * Gromacs exceptions without having extra code in each exception class.
169 * In simple cases, it can be implicitly constructed by passing a simple string
170 * to an exception constructor.
171 * If more complex initialization is necessary, it is possible to explicitly
172 * construct an object of this type and then call other methods to add
173 * information before actually creating the exception object.
176 * With the exception of the reason string, information added with this class
177 * is not currently accessible through any public API, except for calling
178 * printFatalErrorMessage(), formatExceptionMessageToString() or
179 * formatExceptionMessageToFile(). This is not implemented as there is not yet
180 * need for it, and it is not clear what would be the best alternative for the
181 * access. It should be possible to refactor the internal implementation to
182 * suit the needs of such external access without requiring changes in code
183 * that throws these exceptions.
185 * \ingroup module_utility
187 class ExceptionInitializer
191 * Creates an initialized with the given string as the reason.
193 * \param[in] reason Detailed reason for the exception.
194 * \throw std::bad_alloc if out of memory.
196 * This constructor is not explicit to allow constructing exceptions
197 * with a plain string argument given to the constructor without adding
198 * extra code to each exception class.
200 ExceptionInitializer(const char* reason) : reason_(reason) {}
201 //! \copydoc ExceptionInitializer(const char *)
202 ExceptionInitializer(const std::string& reason) : reason_(reason) {}
205 * Returns true if addCurrentExceptionAsNested() has been called.
207 * Provided for convenience for cases where exceptions will be added
208 * conditionally, and the caller wants to check whether any excetions
209 * were actually added.
211 bool hasNestedExceptions() const { return !nested_.empty(); }
213 * Adds the currently caught exception as a nested exception.
215 * May be called multiple times; all provided exceptions will be added
216 * in a list of nested exceptions.
218 * Must not be called outside a catch block.
220 void addCurrentExceptionAsNested() { nested_.push_back(std::current_exception()); }
222 * Adds the specified exception as a nested exception.
224 * May be called multiple times; all provided exceptions will be added
225 * in a list of nested exceptions.
227 * This is equivalent to throwing \p ex and calling
228 * addCurrentExceptionAsNested() in the catch block, but potentially
231 template<class Exception>
232 void addNested(const Exception& ex)
234 nested_.push_back(std::make_exception_ptr(ex));
239 internal::NestedExceptionList nested_;
241 friend class GromacsException;
245 * Base class for all exception objects in Gromacs.
249 class GromacsException : public std::exception
252 // Explicitly declared because some compiler/library combinations warn
253 // about missing noexcept otherwise.
254 ~GromacsException() noexcept override {}
256 GromacsException() = default;
257 GromacsException(const GromacsException&) = default;
258 GromacsException(GromacsException&&) noexcept = default;
259 GromacsException& operator=(const GromacsException&) = default;
260 GromacsException& operator=(GromacsException&&) noexcept = default;
263 * Returns the reason string for the exception.
265 * The return value is the string that was passed to the constructor.
267 const char* what() const noexcept override;
269 * Returns the error code corresponding to the exception type.
271 virtual int errorCode() const = 0;
274 * Returns the value associated with given ExceptionInfo.
276 * \tparam InfoType ExceptionInfo type to get the value for.
277 * \returns Value set for `InfoType`, or `nullptr` if such info has not
282 template<class InfoType>
283 const typename InfoType::value_type* getInfo() const
285 const internal::IExceptionInfo* item = getInfo(typeid(InfoType));
288 GMX_ASSERT(dynamic_cast<const InfoType*>(item) != nullptr,
289 "Invalid exception info item found");
290 return &static_cast<const InfoType*>(item)->value();
296 * Associates extra information with the exception.
298 * \tparam Tag ExceptionInfo tag type.
299 * \tparam T ExceptionInfo value type.
300 * \param[in] item ExceptionInfo to associate.
301 * \throws std::bad_alloc if out of memory.
302 * \throws unspecified any exception thrown by `T` copy construction.
304 * If an item of this type is already associated, it is overwritten.
306 template<class Tag, typename T>
307 void setInfo(const ExceptionInfo<Tag, T>& item)
309 typedef ExceptionInfo<Tag, T> ItemType;
310 internal::ExceptionInfoPointer itemPtr(new ItemType(item));
311 setInfo(typeid(ItemType), std::move(itemPtr));
315 * Adds context information to this exception.
317 * \param[in] context Context string to add.
318 * \throws std::bad_alloc if out of memory.
320 * Typical use is to add additional information higher up in the call
321 * stack using this function in a catch block and the rethrow the
325 * The added information is currently not accessible through what(),
326 * nor through any other means except for calling
327 * printFatalErrorMessage(), formatExceptionMessageToString() or
328 * formatExceptionMessageToFile(). See ExceptionInitializer for more
331 void prependContext(const std::string& context);
335 * Creates an exception object with the provided initializer/reason.
337 * \param[in] details Initializer for the exception.
338 * \throws std::bad_alloc if out of memory.
340 explicit GromacsException(const ExceptionInitializer& details);
343 const internal::IExceptionInfo* getInfo(const std::type_index& index) const;
344 void setInfo(const std::type_index& index, internal::ExceptionInfoPointer&& item);
346 std::shared_ptr<internal::ExceptionData> data_;
350 * Associates extra information with an exception.
352 * \tparam Exception Exception type (must be derived from GromacsException).
353 * \tparam Tag ExceptionInfo tag.
354 * \tparam T ExceptionInfo value type.
355 * \param[in,out] ex Exception to associate the information to.
356 * \param[in] item Information to associate.
359 * The association is done with a templated non-member operator of exactly this
360 * form to make the simple syntax of GMX_THROW() possible. To support this,
361 * this operation needs to:
362 * - Allow setting information in a temporary to support
363 * `GMX_THROW(InvalidInputError(ex))`.
364 * - Return a copy of the same class it takes in. The compiler needs
365 * this information to throw the correct type of exception. This
366 * would be tedious to achieve with a member function (without a
367 * lot of code duplication). Generally, \c ex will be a temporary,
368 * copied twice and returned by value, which the compiler will
369 * typically elide away (and anyway performance is not important
370 * when throwing). We are not using the typical
371 * return-by-const-reference idiom for this operator so that
372 * tooling can reliably see that we are throwing by value.
373 * - Provide convenient syntax for adding multiple items. A non-member
374 * function that would require nested calls would look ugly for such cases.
376 * The reason for the enable_if is that this way, it does not conflict with
377 * other overloads of `operator<<` for ExceptionInfo objects, in case someone
378 * would like to declare those. But currently we do not have such overloads, so
379 * if the enable_if causes problems with some compilers, it can be removed.
381 template<class Exception, class Tag, class T>
382 inline std::enable_if_t<std::is_base_of<GromacsException, Exception>::value, Exception>
383 operator<<(Exception ex, const ExceptionInfo<Tag, T>& item)
390 * Exception class for file I/O errors.
394 class FileIOError : public GromacsException
398 * Creates an exception object with the provided initializer/reason.
400 * \param[in] details Initializer for the exception.
401 * \throws std::bad_alloc if out of memory.
403 * It is possible to call this constructor either with an explicit
404 * ExceptionInitializer object (useful for more complex cases), or
405 * a simple string if only a reason string needs to be provided.
407 explicit FileIOError(const ExceptionInitializer& details) : GromacsException(details) {}
409 int errorCode() const override;
413 * Exception class for user input errors.
415 * Derived classes should be used to indicate the nature of the error instead
416 * of throwing this class directly.
420 class UserInputError : public GromacsException
423 //! \copydoc FileIOError::FileIOError()
424 explicit UserInputError(const ExceptionInitializer& details) : GromacsException(details) {}
428 * Exception class for situations where user input cannot be parsed/understood.
432 class InvalidInputError : public UserInputError
435 //! \copydoc FileIOError::FileIOError()
436 explicit InvalidInputError(const ExceptionInitializer& details) : UserInputError(details) {}
438 int errorCode() const override;
442 * Exception class for situations where user input is inconsistent.
446 class InconsistentInputError : public UserInputError
449 //! \copydoc FileIOError::FileIOError()
450 explicit InconsistentInputError(const ExceptionInitializer& details) : UserInputError(details)
454 int errorCode() const override;
458 * Exception class when a specified tolerance cannot be achieved.
462 class ToleranceError : public GromacsException
466 * Creates an exception object with the provided initializer/reason.
468 * \param[in] details Initializer for the exception.
469 * \throws std::bad_alloc if out of memory.
471 * It is possible to call this constructor either with an explicit
472 * ExceptionInitializer object (useful for more complex cases), or
473 * a simple string if only a reason string needs to be provided.
475 explicit ToleranceError(const ExceptionInitializer& details) : GromacsException(details) {}
477 int errorCode() const override;
481 * Exception class for simulation instabilities.
485 class SimulationInstabilityError : public GromacsException
488 //! \copydoc FileIOError::FileIOError()
489 explicit SimulationInstabilityError(const ExceptionInitializer& details) :
490 GromacsException(details)
494 int errorCode() const override;
498 * Exception class for internal errors.
502 class InternalError : public GromacsException
505 //! \copydoc FileIOError::FileIOError()
506 explicit InternalError(const ExceptionInitializer& details) : GromacsException(details) {}
508 int errorCode() const override;
512 * Exception class for incorrect use of an API.
516 class APIError : public GromacsException
519 //! \copydoc FileIOError::FileIOError()
520 explicit APIError(const ExceptionInitializer& details) : GromacsException(details) {}
522 int errorCode() const override;
526 * Exception class for out-of-range values or indices
530 class RangeError : public GromacsException
533 //! \copydoc FileIOError::FileIOError()
534 explicit RangeError(const ExceptionInitializer& details) : GromacsException(details) {}
536 int errorCode() const override;
540 * Exception class for use of an unimplemented feature.
544 class NotImplementedError : public APIError
547 //! \copydoc FileIOError::FileIOError()
548 explicit NotImplementedError(const ExceptionInitializer& details) : APIError(details) {}
550 int errorCode() const override;
553 /*! \brief Exception class for use when ensuring that MPI ranks to throw
554 * in a coordinated fashion.
556 * Generally all ranks that can throw would need to check for whether
557 * an exception has been caught, communicate whether any rank caught,
558 * then all throw one of these, with either a string that describes
559 * any exception caught on that rank, or a generic string.
563 class ParallelConsistencyError : public APIError
566 //! \copydoc FileIOError::FileIOError()
567 explicit ParallelConsistencyError(const ExceptionInitializer& details) : APIError(details) {}
569 int errorCode() const override;
573 * Macro for throwing an exception.
575 * \param[in] e Exception object to throw.
577 * Using this macro instead of \c throw directly makes it possible to uniformly
578 * attach information into the exception objects.
579 * \p e should evaluate to an instance of an object derived from
586 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
590 #define GMX_THROW(e) \
591 throw(e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
594 * Macro for throwing an exception based on errno.
596 * \param[in] e Exception object to throw.
597 * \param[in] syscall Name of the syscall that returned the error.
598 * \param[in] err errno value returned by the syscall.
600 * This macro provides a convenience interface for throwing an exception to
601 * report an error based on a errno value. In addition to adding the necessary
602 * information to the exception object, the macro also ensures that \p errno is
603 * evaluated before, e.g., the constructor of \p e may call other functions
604 * that could overwrite the errno value.
605 * \p e should evaluate to an instance of an object derived from
608 * Typical usage (note that gmx::File wraps this particular case):
610 FILE *fp = fopen("filename.txt", "r");
613 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
617 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
620 int stored_errno_ = (err); \
621 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
622 << gmx::ExceptionInfoApiFunction(syscall)); \
624 // TODO: Add an equivalent macro for Windows GetLastError
627 * Formats a standard fatal error message for reporting an exception.
629 * \param[in] fp %File to format the message to.
630 * \param[in] ex Exception to format.
632 * Does not throw. If memory allocation fails or some other error occurs
633 * while formatting the error, tries to print a reasonable alternative message.
635 * Normal usage in Gromacs command-line programs is like this:
637 int main(int argc, char *argv[])
639 gmx::init(&argc, &argv);
642 // The actual code for the program
645 catch (const std::exception &ex)
647 gmx::printFatalErrorMessage(stderr, ex);
648 return gmx::processExceptionAtExit(ex);
653 void printFatalErrorMessage(FILE* fp, const std::exception& ex);
655 * Formats an error message for reporting an exception.
657 * \param[in] ex Exception to format.
658 * \returns Formatted string containing details of \p ex.
659 * \throws std::bad_alloc if out of memory.
661 std::string formatExceptionMessageToString(const std::exception& ex);
663 * Formats an error message for reporting an exception.
665 * \param fp %File to write the message to.
666 * \param[in] ex Exception to format.
667 * \throws std::bad_alloc if out of memory.
669 void formatExceptionMessageToFile(FILE* fp, const std::exception& ex);
671 * Formats an error message for reporting an exception.
673 * \param writer Writer to use for writing the message.
674 * \param[in] ex Exception to format.
675 * \throws std::bad_alloc if out of memory.
677 void formatExceptionMessageToWriter(TextWriter* writer, const std::exception& ex);
679 * Handles an exception that is causing the program to terminate.
681 * \param[in] ex Exception that is the cause for terminating the program.
682 * \returns Return code to return from main().
684 * This method should be called as the last thing before terminating the
685 * program because of an exception. It exists to terminate the program as
686 * gracefully as possible in the case of MPI processing (but the current
687 * implementation always calls MPI_Abort()).
689 * See printFatalErrorMessage() for example usage.
693 int processExceptionAtExit(const std::exception& ex);
696 * Helper function for terminating the program on an exception.
698 * \param[in] ex Exception that is the cause for terminating the program.
700 * Does not throw, and does not return.
702 [[noreturn]] void processExceptionAsFatalError(const std::exception& ex);
705 * Macro for catching exceptions at C++ -> C boundary.
707 * This macro is intended for uniform handling of exceptions when C++ code is
708 * called from C code within Gromacs. Since most existing code is written
709 * using the assumption that fatal errors terminate the program, this macro
710 * implements this behavior for exceptions. It should only be used in cases
711 * where the error cannot be propagated upwards using return values or such.
713 * Having this as a macro instead of having the same code in each place makes
714 * it easy to 1) find all such locations in the code, and 2) change the exact
715 * behavior if needed.
723 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
726 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
727 catch (const std::exception& ex) { ::gmx::processExceptionAsFatalError(ex); }