2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015,2016,2018, 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/current_function.h"
63 #include "gromacs/utility/gmxassert.h"
72 //! Internal container type for storing a list of nested exceptions.
73 typedef std::vector<std::exception_ptr> NestedExceptionList;
77 * Base class for ExceptionInfo.
79 * This class only provides a way to store different ExceptionInfo objects in
80 * the same container. Actual access to the ExceptionInfo items is handled by
81 * downcasting, after looking up the correct item based on its type.
83 * \ingroup module_utility
88 virtual ~IExceptionInfo();
89 GMX_DEFAULT_CONSTRUCTORS(IExceptionInfo);
92 //! Smart pointer to manage IExceptionInfo ownership.
93 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer;
97 } // namespace internal
99 //! \addtogroup module_utility
103 * Stores additional context information for exceptions.
105 * \tparam Tag Tag type (typically, a forward-declared struct that is not
106 * defined anywhere) that makes all ExceptionInfo types unique, even if
107 * they have the same value type.
108 * \tparam T Type of value this object stores.
109 * Needs to be copy-constructible.
111 * Example of declaring a new info type that stores an integer:
113 typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo;
118 template <class Tag, typename T>
119 class ExceptionInfo : public internal::IExceptionInfo
122 //! The type of value stored in this object.
123 typedef T value_type;
125 //! Creates an info object from given value.
126 explicit ExceptionInfo(const T &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)
146 : func(func), file(file), line(line)
150 //! Function where the throw occurred.
152 //! File where the throw occurred.
154 //! Line number where the throw occurred.
158 //! Stores `errno` value that triggered the exception.
159 typedef ExceptionInfo<struct ExceptionInfoErrno_, int>
161 //! Stores the function name that returned the `errno` in ExceptionInfoErrno.
162 typedef ExceptionInfo<struct ExceptionInfoApiFunc_, const char *>
163 ExceptionInfoApiFunction;
164 //! Stores the location where the exception was thrown.
165 typedef ExceptionInfo<struct ExceptionInfoLocation_, ThrowLocation>
166 ExceptionInfoLocation;
169 * Provides information for Gromacs exception constructors.
171 * This class exists to implement common functionality for initializing all
172 * Gromacs exceptions without having extra code in each exception class.
173 * In simple cases, it can be implicitly constructed by passing a simple string
174 * to an exception constructor.
175 * If more complex initialization is necessary, it is possible to explicitly
176 * construct an object of this type and then call other methods to add
177 * information before actually creating the exception object.
180 * With the exception of the reason string, information added with this class
181 * is not currently accessible through any public API, except for calling
182 * printFatalErrorMessage(), formatExceptionMessageToString() or
183 * formatExceptionMessageToFile(). This is not implemented as there is not yet
184 * need for it, and it is not clear what would be the best alternative for the
185 * access. It should be possible to refactor the internal implementation to
186 * suit the needs of such external access without requiring changes in code
187 * that throws these exceptions.
189 * \ingroup module_utility
191 class ExceptionInitializer
195 * Creates an initialized with the given string as the reason.
197 * \param[in] reason Detailed reason for the exception.
198 * \throw std::bad_alloc if out of memory.
200 * This constructor is not explicit to allow constructing exceptions
201 * with a plain string argument given to the constructor without adding
202 * extra code to each exception class.
204 ExceptionInitializer(const char *reason)
208 //! \copydoc ExceptionInitializer(const char *)
209 ExceptionInitializer(const std::string &reason)
215 * Returns true if addCurrentExceptionAsNested() has been called.
217 * Provided for convenience for cases where exceptions will be added
218 * conditionally, and the caller wants to check whether any excetions
219 * were actually added.
221 bool hasNestedExceptions() const { return !nested_.empty(); }
223 * Adds the currently caught exception as a nested exception.
225 * May be called multiple times; all provided exceptions will be added
226 * in a list of nested exceptions.
228 * Must not be called outside a catch block.
230 void addCurrentExceptionAsNested()
232 nested_.push_back(std::current_exception());
235 * Adds the specified exception as a nested exception.
237 * May be called multiple times; all provided exceptions will be added
238 * in a list of nested exceptions.
240 * This is equivalent to throwing \p ex and calling
241 * addCurrentExceptionAsNested() in the catch block, but potentially
244 template <class Exception>
245 void addNested(const Exception &ex)
247 nested_.push_back(std::make_exception_ptr(ex));
252 internal::NestedExceptionList nested_;
254 friend class GromacsException;
258 * Base class for all exception objects in Gromacs.
262 class GromacsException : public std::exception
265 // Explicitly declared because some compiler/library combinations warn
266 // about missing noexcept otherwise.
267 virtual ~GromacsException() noexcept {}
269 GMX_DEFAULT_CONSTRUCTORS(GromacsException);
272 * Returns the reason string for the exception.
274 * The return value is the string that was passed to the constructor.
276 virtual const char *what() const noexcept;
278 * Returns the error code corresponding to the exception type.
280 virtual int errorCode() const = 0;
283 * Returns the value associated with given ExceptionInfo.
285 * \tparam InfoType ExceptionInfo type to get the value for.
286 * \returns Value set for `InfoType`, or `nullptr` if such info has not
291 template <class InfoType>
292 const typename InfoType::value_type *getInfo() const
294 const internal::IExceptionInfo *item = getInfo(typeid(InfoType));
297 GMX_ASSERT(dynamic_cast<const InfoType *>(item) != nullptr,
298 "Invalid exception info item found");
299 return &static_cast<const InfoType *>(item)->value();
305 * Associates extra information with the exception.
307 * \tparam Tag ExceptionInfo tag type.
308 * \tparam T ExceptionInfo value type.
309 * \param[in] item ExceptionInfo to associate.
310 * \throws std::bad_alloc if out of memory.
311 * \throws unspecified any exception thrown by `T` copy construction.
313 * If an item of this type is already associated, it is overwritten.
315 template <class Tag, typename T>
316 void setInfo(const ExceptionInfo<Tag, T> &item)
318 typedef ExceptionInfo<Tag, T> ItemType;
319 internal::ExceptionInfoPointer itemPtr(new ItemType(item));
320 setInfo(typeid(ItemType), std::move(itemPtr));
324 * Adds context information to this exception.
326 * \param[in] context Context string to add.
327 * \throws std::bad_alloc if out of memory.
329 * Typical use is to add additional information higher up in the call
330 * stack using this function in a catch block and the rethrow the
334 * The added information is currently not accessible through what(),
335 * nor through any other means except for calling
336 * printFatalErrorMessage(), formatExceptionMessageToString() or
337 * formatExceptionMessageToFile(). See ExceptionInitializer for more
340 void prependContext(const std::string &context);
344 * Creates an exception object with the provided initializer/reason.
346 * \param[in] details Initializer for the exception.
347 * \throws std::bad_alloc if out of memory.
349 explicit GromacsException(const ExceptionInitializer &details);
352 const internal::IExceptionInfo *getInfo(const std::type_index &index) const;
353 void setInfo(const std::type_index &index, internal::ExceptionInfoPointer &&item);
355 std::shared_ptr<internal::ExceptionData> data_;
359 * Associates extra information with an exception.
361 * \tparam Exception Exception type (must be derived from GromacsException).
362 * \tparam Tag ExceptionInfo tag.
363 * \tparam T ExceptionInfo value type.
364 * \param[in,out] ex Exception to associate the information to.
365 * \param[in] item Information to associate.
368 * The association is done with a templated non-member operator of exactly this
369 * form to make the simple syntax of GMX_THROW() possible. To support this,
370 * this operation needs to:
371 * - Allow setting information in a temporary to support
372 * `GMX_THROW(InvalidInputError(ex))`.
373 * - Return a copy of the same class it takes in. The compiler needs
374 * this information to throw the correct type of exception. This
375 * would be tedious to achieve with a member function (without a
376 * lot of code duplication). Generally, \c ex will be a temporary,
377 * copied twice and returned by value, which the compiler will
378 * typically elide away (and anyway performance is not important
379 * when throwing). We are not using the typical
380 * return-by-const-reference idiom for this operator so that
381 * tooling can reliably see that we are throwing by value.
382 * - Provide convenient syntax for adding multiple items. A non-member
383 * function that would require nested calls would look ugly for such cases.
385 * The reason for the enable_if is that this way, it does not conflict with
386 * other overloads of `operator<<` for ExceptionInfo objects, in case someone
387 * would like to declare those. But currently we do not have such overloads, so
388 * if the enable_if causes problems with some compilers, it can be removed.
390 template <class Exception, class Tag, class T>
392 typename std::enable_if<std::is_base_of<GromacsException, Exception>::value, Exception>::type
393 operator<<(Exception ex, const ExceptionInfo<Tag, T> &item)
400 * Exception class for file I/O errors.
404 class FileIOError : public GromacsException
408 * Creates an exception object with the provided initializer/reason.
410 * \param[in] details Initializer for the exception.
411 * \throws std::bad_alloc if out of memory.
413 * It is possible to call this constructor either with an explicit
414 * ExceptionInitializer object (useful for more complex cases), or
415 * a simple string if only a reason string needs to be provided.
417 explicit FileIOError(const ExceptionInitializer &details)
418 : GromacsException(details) {}
420 virtual int errorCode() const;
424 * Exception class for user input errors.
426 * Derived classes should be used to indicate the nature of the error instead
427 * of throwing this class directly.
431 class UserInputError : public GromacsException
434 //! \copydoc FileIOError::FileIOError()
435 explicit UserInputError(const ExceptionInitializer &details)
436 : GromacsException(details) {}
440 * Exception class for situations where user input cannot be parsed/understood.
444 class InvalidInputError : public UserInputError
447 //! \copydoc FileIOError::FileIOError()
448 explicit InvalidInputError(const ExceptionInitializer &details)
449 : UserInputError(details) {}
451 virtual int errorCode() const;
455 * Exception class for situations where user input is inconsistent.
459 class InconsistentInputError : public UserInputError
462 //! \copydoc FileIOError::FileIOError()
463 explicit InconsistentInputError(const ExceptionInitializer &details)
464 : UserInputError(details) {}
466 virtual int errorCode() const;
470 * Exception class when a specified tolerance cannot be achieved.
474 class ToleranceError : public GromacsException
478 * Creates an exception object with the provided initializer/reason.
480 * \param[in] details Initializer for the exception.
481 * \throws std::bad_alloc if out of memory.
483 * It is possible to call this constructor either with an explicit
484 * ExceptionInitializer object (useful for more complex cases), or
485 * a simple string if only a reason string needs to be provided.
487 explicit ToleranceError(const ExceptionInitializer &details)
488 : GromacsException(details) {}
490 virtual int errorCode() const;
494 * Exception class for simulation instabilities.
498 class SimulationInstabilityError : public GromacsException
501 //! \copydoc FileIOError::FileIOError()
502 explicit SimulationInstabilityError(const ExceptionInitializer &details)
503 : GromacsException(details) {}
505 virtual int errorCode() const;
509 * Exception class for internal errors.
513 class InternalError : public GromacsException
516 //! \copydoc FileIOError::FileIOError()
517 explicit InternalError(const ExceptionInitializer &details)
518 : GromacsException(details) {}
520 virtual int errorCode() const;
524 * Exception class for incorrect use of an API.
528 class APIError : public GromacsException
531 //! \copydoc FileIOError::FileIOError()
532 explicit APIError(const ExceptionInitializer &details)
533 : GromacsException(details) {}
535 virtual int errorCode() const;
539 * Exception class for out-of-range values or indices
543 class RangeError : public GromacsException
546 //! \copydoc FileIOError::FileIOError()
547 explicit RangeError(const ExceptionInitializer &details)
548 : GromacsException(details) {}
550 virtual int errorCode() const;
554 * Exception class for use of an unimplemented feature.
558 class NotImplementedError : public APIError
561 //! \copydoc FileIOError::FileIOError()
562 explicit NotImplementedError(const ExceptionInitializer &details)
563 : APIError(details) {}
565 virtual int errorCode() const;
569 * Macro for throwing an exception.
571 * \param[in] e Exception object to throw.
573 * Using this macro instead of \c throw directly makes it possible to uniformly
574 * attach information into the exception objects.
575 * \p e should evaluate to an instance of an object derived from
582 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
586 #define GMX_THROW(e) \
587 throw (e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
590 * Macro for throwing an exception based on errno.
592 * \param[in] e Exception object to throw.
593 * \param[in] syscall Name of the syscall that returned the error.
594 * \param[in] err errno value returned by the syscall.
596 * This macro provides a convenience interface for throwing an exception to
597 * report an error based on a errno value. In addition to adding the necessary
598 * information to the exception object, the macro also ensures that \p errno is
599 * evaluated before, e.g., the constructor of \p e may call other functions
600 * that could overwrite the errno value.
601 * \p e should evaluate to an instance of an object derived from
604 * Typical usage (note that gmx::File wraps this particular case):
606 FILE *fp = fopen("filename.txt", "r");
609 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
613 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
615 int stored_errno_ = (err); \
616 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
617 << gmx::ExceptionInfoApiFunction(syscall)); \
619 //TODO: Add an equivalent macro for Windows GetLastError
622 * Formats a standard fatal error message for reporting an exception.
624 * \param[in] fp %File to format the message to.
625 * \param[in] ex Exception to format.
627 * Does not throw. If memory allocation fails or some other error occurs
628 * while formatting the error, tries to print a reasonable alternative message.
630 * Normal usage in Gromacs command-line programs is like this:
632 int main(int argc, char *argv[])
634 gmx::init(&argc, &argv);
637 // The actual code for the program
640 catch (const std::exception &ex)
642 gmx::printFatalErrorMessage(stderr, ex);
643 return gmx::processExceptionAtExit(ex);
648 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
650 * Formats an error message for reporting an exception.
652 * \param[in] ex Exception to format.
653 * \returns Formatted string containing details of \p ex.
654 * \throws std::bad_alloc if out of memory.
656 std::string formatExceptionMessageToString(const std::exception &ex);
658 * Formats an error message for reporting an exception.
660 * \param fp %File to write the message to.
661 * \param[in] ex Exception to format.
662 * \throws std::bad_alloc if out of memory.
664 void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
666 * Formats an error message for reporting an exception.
668 * \param writer Writer to use for writing the message.
669 * \param[in] ex Exception to format.
670 * \throws std::bad_alloc if out of memory.
672 void formatExceptionMessageToWriter(TextWriter *writer,
673 const std::exception &ex);
675 * Handles an exception that is causing the program to terminate.
677 * \param[in] ex Exception that is the cause for terminating the program.
678 * \returns Return code to return from main().
680 * This method should be called as the last thing before terminating the
681 * program because of an exception. It exists to terminate the program as
682 * gracefully as possible in the case of MPI processing (but the current
683 * implementation always calls MPI_Abort()).
685 * See printFatalErrorMessage() for example usage.
689 int processExceptionAtExit(const std::exception &ex);
692 * Helper function for terminating the program on an exception.
694 * \param[in] ex Exception that is the cause for terminating the program.
696 * Does not throw, and does not return.
698 gmx_noreturn void processExceptionAsFatalError(const std::exception &ex);
701 * Macro for catching exceptions at C++ -> C boundary.
703 * This macro is intended for uniform handling of exceptions when C++ code is
704 * called from C code within Gromacs. Since most existing code is written
705 * using the assumption that fatal errors terminate the program, this macro
706 * implements this behavior for exceptions. It should only be used in cases
707 * where the error cannot be propagated upwards using return values or such.
709 * Having this as a macro instead of having the same code in each place makes
710 * it easy to 1) find all such locations in the code, and 2) change the exact
711 * behavior if needed.
719 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
722 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
723 catch (const std::exception &ex) { \
724 ::gmx::processExceptionAsFatalError(ex); \