2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2011,2012,2013,2014,2015,2016, 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))`. This is the reason for taking a
373 * const reference and the `const_cast`.
374 * - Return the same reference it takes in, instead of a base class.
375 * The compiler needs this information to throw the correct type of
376 * exception. This would be tedious to achieve with a member function
377 * (without a lot of code duplication).
378 * - Provide convenient syntax for adding multiple items. A non-member
379 * function that would require nested calls would look ugly for such cases.
381 * The reason for the enable_if is that this way, it does not conflict with
382 * other overloads of `operator<<` for ExceptionInfo objects, in case someone
383 * would like to declare those. But currently we do not have such overloads, so
384 * if the enable_if causes problems with some compilers, it can be removed.
386 template <class Exception
, class Tag
, class T
>
388 typename
std::enable_if
<std::is_base_of
<GromacsException
, Exception
>::value
, const Exception
&>::type
389 operator<<(const Exception
&ex
, const ExceptionInfo
<Tag
, T
> &item
)
391 const_cast<Exception
&>(ex
).setInfo(item
);
396 * Exception class for file I/O errors.
400 class FileIOError
: public GromacsException
404 * Creates an exception object with the provided initializer/reason.
406 * \param[in] details Initializer for the exception.
407 * \throws std::bad_alloc if out of memory.
409 * It is possible to call this constructor either with an explicit
410 * ExceptionInitializer object (useful for more complex cases), or
411 * a simple string if only a reason string needs to be provided.
413 explicit FileIOError(const ExceptionInitializer
&details
)
414 : GromacsException(details
) {}
416 virtual int errorCode() const;
420 * Exception class for user input errors.
422 * Derived classes should be used to indicate the nature of the error instead
423 * of throwing this class directly.
427 class UserInputError
: public GromacsException
430 //! \copydoc FileIOError::FileIOError()
431 explicit UserInputError(const ExceptionInitializer
&details
)
432 : GromacsException(details
) {}
436 * Exception class for situations where user input cannot be parsed/understood.
440 class InvalidInputError
: public UserInputError
443 //! \copydoc FileIOError::FileIOError()
444 explicit InvalidInputError(const ExceptionInitializer
&details
)
445 : UserInputError(details
) {}
447 virtual int errorCode() const;
451 * Exception class for situations where user input is inconsistent.
455 class InconsistentInputError
: public UserInputError
458 //! \copydoc FileIOError::FileIOError()
459 explicit InconsistentInputError(const ExceptionInitializer
&details
)
460 : UserInputError(details
) {}
462 virtual int errorCode() const;
466 * Exception class when a specified tolerance cannot be achieved.
470 class ToleranceError
: public GromacsException
474 * Creates an exception object with the provided initializer/reason.
476 * \param[in] details Initializer for the exception.
477 * \throws std::bad_alloc if out of memory.
479 * It is possible to call this constructor either with an explicit
480 * ExceptionInitializer object (useful for more complex cases), or
481 * a simple string if only a reason string needs to be provided.
483 explicit ToleranceError(const ExceptionInitializer
&details
)
484 : GromacsException(details
) {}
486 virtual int errorCode() const;
490 * Exception class for simulation instabilities.
494 class SimulationInstabilityError
: public GromacsException
497 //! \copydoc FileIOError::FileIOError()
498 explicit SimulationInstabilityError(const ExceptionInitializer
&details
)
499 : GromacsException(details
) {}
501 virtual int errorCode() const;
505 * Exception class for internal errors.
509 class InternalError
: public GromacsException
512 //! \copydoc FileIOError::FileIOError()
513 explicit InternalError(const ExceptionInitializer
&details
)
514 : GromacsException(details
) {}
516 virtual int errorCode() const;
520 * Exception class for incorrect use of an API.
524 class APIError
: public GromacsException
527 //! \copydoc FileIOError::FileIOError()
528 explicit APIError(const ExceptionInitializer
&details
)
529 : GromacsException(details
) {}
531 virtual int errorCode() const;
535 * Exception class for out-of-range values or indices
539 class RangeError
: public GromacsException
542 //! \copydoc FileIOError::FileIOError()
543 explicit RangeError(const ExceptionInitializer
&details
)
544 : GromacsException(details
) {}
546 virtual int errorCode() const;
550 * Exception class for use of an unimplemented feature.
554 class NotImplementedError
: public APIError
557 //! \copydoc FileIOError::FileIOError()
558 explicit NotImplementedError(const ExceptionInitializer
&details
)
559 : APIError(details
) {}
561 virtual int errorCode() const;
565 * Macro for throwing an exception.
567 * \param[in] e Exception object to throw.
569 * Using this macro instead of \c throw directly makes it possible to uniformly
570 * attach information into the exception objects.
571 * \p e should evaluate to an instance of an object derived from
578 GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
582 #define GMX_THROW(e) \
583 throw (e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
586 * Macro for throwing an exception based on errno.
588 * \param[in] e Exception object to throw.
589 * \param[in] syscall Name of the syscall that returned the error.
590 * \param[in] err errno value returned by the syscall.
592 * This macro provides a convenience interface for throwing an exception to
593 * report an error based on a errno value. In addition to adding the necessary
594 * information to the exception object, the macro also ensures that \p errno is
595 * evaluated before, e.g., the constructor of \p e may call other functions
596 * that could overwrite the errno value.
597 * \p e should evaluate to an instance of an object derived from
600 * Typical usage (note that gmx::File wraps this particular case):
602 FILE *fp = fopen("filename.txt", "r");
605 GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
609 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
611 int stored_errno_ = (err); \
612 GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
613 << gmx::ExceptionInfoApiFunction(syscall)); \
615 //TODO: Add an equivalent macro for Windows GetLastError
618 * Formats a standard fatal error message for reporting an exception.
620 * \param[in] fp %File to format the message to.
621 * \param[in] ex Exception to format.
623 * Does not throw. If memory allocation fails or some other error occurs
624 * while formatting the error, tries to print a reasonable alternative message.
626 * Normal usage in Gromacs command-line programs is like this:
628 int main(int argc, char *argv[])
630 gmx::init(&argc, &argv);
633 // The actual code for the program
636 catch (const std::exception &ex)
638 gmx::printFatalErrorMessage(stderr, ex);
639 return gmx::processExceptionAtExit(ex);
644 void printFatalErrorMessage(FILE *fp
, const std::exception
&ex
);
646 * Formats an error message for reporting an exception.
648 * \param[in] ex Exception to format.
649 * \returns Formatted string containing details of \p ex.
650 * \throws std::bad_alloc if out of memory.
652 std::string
formatExceptionMessageToString(const std::exception
&ex
);
654 * Formats an error message for reporting an exception.
656 * \param fp %File to write the message to.
657 * \param[in] ex Exception to format.
658 * \throws std::bad_alloc if out of memory.
660 void formatExceptionMessageToFile(FILE *fp
, const std::exception
&ex
);
662 * Formats an error message for reporting an exception.
664 * \param writer Writer to use for writing the message.
665 * \param[in] ex Exception to format.
666 * \throws std::bad_alloc if out of memory.
668 void formatExceptionMessageToWriter(TextWriter
*writer
,
669 const std::exception
&ex
);
671 * Handles an exception that is causing the program to terminate.
673 * \param[in] ex Exception that is the cause for terminating the program.
674 * \returns Return code to return from main().
676 * This method should be called as the last thing before terminating the
677 * program because of an exception. It exists to terminate the program as
678 * gracefully as possible in the case of MPI processing (but the current
679 * implementation always calls MPI_Abort()).
681 * See printFatalErrorMessage() for example usage.
685 int processExceptionAtExit(const std::exception
&ex
);
688 * Helper function for terminating the program on an exception.
690 * \param[in] ex Exception that is the cause for terminating the program.
692 * Does not throw, and does not return.
694 gmx_noreturn
void processExceptionAsFatalError(const std::exception
&ex
);
697 * Macro for catching exceptions at C++ -> C boundary.
699 * This macro is intended for uniform handling of exceptions when C++ code is
700 * called from C code within Gromacs. Since most existing code is written
701 * using the assumption that fatal errors terminate the program, this macro
702 * implements this behavior for exceptions. It should only be used in cases
703 * where the error cannot be propagated upwards using return values or such.
705 * Having this as a macro instead of having the same code in each place makes
706 * it easy to 1) find all such locations in the code, and 2) change the exact
707 * behavior if needed.
715 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
718 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
719 catch (const std::exception &ex) { \
720 ::gmx::processExceptionAsFatalError(ex); \