1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
9  *
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.
14  *
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.
19  *
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.
24  *
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.
32  *
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.
35  */
36 /*! \file
37  * \brief
38  * Declares common exception classes and macros for fatal error handling.
39  *
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.
43  *
44  * \author Teemu Murtola <teemu.murtola@gmail.com>
45  * \inpublicapi
46  * \ingroup module_utility
47  */
48 #ifndef GMX_UTILITY_EXCEPTIONS_H
49 #define GMX_UTILITY_EXCEPTIONS_H
50 
51 #include <cstdio>
52 #include <cstdlib>
53 
54 #include <exception>
55 #include <memory>
56 #include <string>
57 #include <type_traits>
58 #include <typeindex>
59 #include <vector>
60 
61 #include "gromacs/utility/basedefinitions.h"
62 #include "gromacs/utility/gmxassert.h"
63 
64 namespace gmx
65 {
66 
67 class TextWriter;
68 
69 namespace internal
70 {
71 //! Internal container type for storing a list of nested exceptions.
72 typedef std::vector<std::exception_ptr> NestedExceptionList;
73 
74 /*! \internal
75  * \brief
76  * Base class for ExceptionInfo.
77  *
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.
81  *
82  * \ingroup module_utility
83  */
84 class IExceptionInfo
85 {
86 public:
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;
93 };
94 
95 //! Smart pointer to manage IExceptionInfo ownership.
96 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer;
97 
98 class ExceptionData;
99 
100 } // namespace internal
101 
102 //! \addtogroup module_utility
103 //! \{
104 
105 /*! \brief
106  * Stores additional context information for exceptions.
107  *
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.
113  *
114  * Example of declaring a new info type that stores an integer:
115  * \code
116    typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo;
117    \endcode
118  *
119  * \inpublicapi
120  */
121 template<class Tag, typename T>
122 class ExceptionInfo : public internal::IExceptionInfo
123 {
124 public:
125     //! The type of value stored in this object.
126     typedef T value_type;
127 
128     //! Creates an info object from given value.
ExceptionInfo(const T & value)129     explicit ExceptionInfo(const T& value) : value_(value) {}
130 
131     //! Returns the stored value.
value()132     const T& value() const { return value_; }
133 
134 private:
135     T value_;
136 };
137 
138 /*! \internal
139  * \brief
140  * Stores the location from which an exception was thrown.
141  */
142 struct ThrowLocation
143 {
144     //! Creates an object for storing the throw location.
ThrowLocationThrowLocation145     ThrowLocation(const char* func, const char* file, int line) : func(func), file(file), line(line)
146     {
147     }
148 
149     //! Function where the throw occurred.
150     const char* func;
151     //! File where the throw occurred.
152     const char* file;
153     //! Line number where the throw occurred.
154     int line;
155 };
156 
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;
163 
164 /*! \brief
165  * Provides information for Gromacs exception constructors.
166  *
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.
174  *
175  * \todo
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.
184  *
185  * \ingroup module_utility
186  */
187 class ExceptionInitializer
188 {
189 public:
190     /*! \brief
191      * Creates an initialized with the given string as the reason.
192      *
193      * \param[in] reason  Detailed reason for the exception.
194      * \throw     std::bad_alloc if out of memory.
195      *
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.
199      */
ExceptionInitializer(const char * reason)200     ExceptionInitializer(const char* reason) : reason_(reason) {}
201     //! \copydoc ExceptionInitializer(const char *)
ExceptionInitializer(const std::string & reason)202     ExceptionInitializer(const std::string& reason) : reason_(reason) {}
203 
204     /*! \brief
205      * Returns true if addCurrentExceptionAsNested() has been called.
206      *
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.
210      */
hasNestedExceptions()211     bool hasNestedExceptions() const { return !nested_.empty(); }
212     /*! \brief
213      * Adds the currently caught exception as a nested exception.
214      *
215      * May be called multiple times; all provided exceptions will be added
216      * in a list of nested exceptions.
217      *
218      * Must not be called outside a catch block.
219      */
addCurrentExceptionAsNested()220     void addCurrentExceptionAsNested() { nested_.push_back(std::current_exception()); }
221     /*! \brief
222      * Adds the specified exception as a nested exception.
223      *
224      * May be called multiple times; all provided exceptions will be added
225      * in a list of nested exceptions.
226      *
227      * This is equivalent to throwing \p ex and calling
228      * addCurrentExceptionAsNested() in the catch block, but potentially
229      * more efficient.
230      */
231     template<class Exception>
addNested(const Exception & ex)232     void addNested(const Exception& ex)
233     {
234         nested_.push_back(std::make_exception_ptr(ex));
235     }
236 
237 private:
238     std::string                   reason_;
239     internal::NestedExceptionList nested_;
240 
241     friend class GromacsException;
242 };
243 
244 /*! \brief
245  * Base class for all exception objects in Gromacs.
246  *
247  * \inpublicapi
248  */
249 class GromacsException : public std::exception
250 {
251 public:
252     // Explicitly declared because some compiler/library combinations warn
253     // about missing noexcept otherwise.
~GromacsException()254     ~GromacsException() noexcept override {}
255 
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;
261 
262     /*! \brief
263      * Returns the reason string for the exception.
264      *
265      * The return value is the string that was passed to the constructor.
266      */
267     const char* what() const noexcept override;
268     /*! \brief
269      * Returns the error code corresponding to the exception type.
270      */
271     virtual int errorCode() const = 0;
272 
273     /*! \brief
274      * Returns the value associated with given ExceptionInfo.
275      *
276      * \tparam  InfoType  ExceptionInfo type to get the value for.
277      * \returns Value set for `InfoType`, or `nullptr` if such info has not
278      *     been set.
279      *
280      * Does not throw.
281      */
282     template<class InfoType>
getInfo()283     const typename InfoType::value_type* getInfo() const
284     {
285         const internal::IExceptionInfo* item = getInfo(typeid(InfoType));
286         if (item != nullptr)
287         {
288             GMX_ASSERT(dynamic_cast<const InfoType*>(item) != nullptr,
289                        "Invalid exception info item found");
290             return &static_cast<const InfoType*>(item)->value();
291         }
292         return nullptr;
293     }
294 
295     /*! \brief
296      * Associates extra information with the exception.
297      *
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.
303      *
304      * If an item of this type is already associated, it is overwritten.
305      */
306     template<class Tag, typename T>
setInfo(const ExceptionInfo<Tag,T> & item)307     void setInfo(const ExceptionInfo<Tag, T>& item)
308     {
309         typedef ExceptionInfo<Tag, T>  ItemType;
310         internal::ExceptionInfoPointer itemPtr(new ItemType(item));
311         setInfo(typeid(ItemType), std::move(itemPtr));
312     }
313 
314     /*! \brief
315      * Adds context information to this exception.
316      *
317      * \param[in] context  Context string to add.
318      * \throws    std::bad_alloc if out of memory.
319      *
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
322      * exception.
323      *
324      * \todo
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
329      * discussion.
330      */
331     void prependContext(const std::string& context);
332 
333 protected:
334     /*! \brief
335      * Creates an exception object with the provided initializer/reason.
336      *
337      * \param[in] details  Initializer for the exception.
338      * \throws    std::bad_alloc if out of memory.
339      */
340     explicit GromacsException(const ExceptionInitializer& details);
341 
342 private:
343     const internal::IExceptionInfo* getInfo(const std::type_index& index) const;
344     void setInfo(const std::type_index& index, internal::ExceptionInfoPointer&& item);
345 
346     std::shared_ptr<internal::ExceptionData> data_;
347 };
348 
349 /*! \brief
350  * Associates extra information with an exception.
351  *
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.
357  *
358  * \internal
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.
375  *
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.
380  *
381  * \todo Use std::is_base_of_v when CUDA 11 is a requirement.
382  */
383 template<class Exception, class Tag, class T>
384 inline std::enable_if_t<std::is_base_of<GromacsException, Exception>::value, Exception>
385 operator<<(Exception ex, const ExceptionInfo<Tag, T>& item)
386 {
387     ex.setInfo(item);
388     return ex;
389 }
390 
391 /*! \brief
392  * Exception class for file I/O errors.
393  *
394  * \inpublicapi
395  */
396 class FileIOError : public GromacsException
397 {
398 public:
399     /*! \brief
400      * Creates an exception object with the provided initializer/reason.
401      *
402      * \param[in] details  Initializer for the exception.
403      * \throws    std::bad_alloc if out of memory.
404      *
405      * It is possible to call this constructor either with an explicit
406      * ExceptionInitializer object (useful for more complex cases), or
407      * a simple string if only a reason string needs to be provided.
408      */
FileIOError(const ExceptionInitializer & details)409     explicit FileIOError(const ExceptionInitializer& details) : GromacsException(details) {}
410 
411     int errorCode() const override;
412 };
413 
414 /*! \brief
415  * Exception class for user input errors.
416  *
417  * Derived classes should be used to indicate the nature of the error instead
418  * of throwing this class directly.
419  *
420  * \inpublicapi
421  */
422 class UserInputError : public GromacsException
423 {
424 protected:
425     //! \copydoc FileIOError::FileIOError()
UserInputError(const ExceptionInitializer & details)426     explicit UserInputError(const ExceptionInitializer& details) : GromacsException(details) {}
427 };
428 
429 /*! \brief
430  * Exception class for situations where user input cannot be parsed/understood.
431  *
432  * \inpublicapi
433  */
434 class InvalidInputError : public UserInputError
435 {
436 public:
437     //! \copydoc FileIOError::FileIOError()
InvalidInputError(const ExceptionInitializer & details)438     explicit InvalidInputError(const ExceptionInitializer& details) : UserInputError(details) {}
439 
440     int errorCode() const override;
441 };
442 
443 /*! \brief
444  * Exception class for situations where user input is inconsistent.
445  *
446  * \inpublicapi
447  */
448 class InconsistentInputError : public UserInputError
449 {
450 public:
451     //! \copydoc FileIOError::FileIOError()
InconsistentInputError(const ExceptionInitializer & details)452     explicit InconsistentInputError(const ExceptionInitializer& details) : UserInputError(details)
453     {
454     }
455 
456     int errorCode() const override;
457 };
458 
459 /*! \brief
460  * Exception class when a specified tolerance cannot be achieved.
461  *
462  * \inpublicapi
463  */
464 class ToleranceError : public GromacsException
465 {
466 public:
467     /*! \brief
468      * Creates an exception object with the provided initializer/reason.
469      *
470      * \param[in] details  Initializer for the exception.
471      * \throws    std::bad_alloc if out of memory.
472      *
473      * It is possible to call this constructor either with an explicit
474      * ExceptionInitializer object (useful for more complex cases), or
475      * a simple string if only a reason string needs to be provided.
476      */
ToleranceError(const ExceptionInitializer & details)477     explicit ToleranceError(const ExceptionInitializer& details) : GromacsException(details) {}
478 
479     int errorCode() const override;
480 };
481 
482 /*! \brief
483  * Exception class for simulation instabilities.
484  *
485  * \inpublicapi
486  */
487 class SimulationInstabilityError : public GromacsException
488 {
489 public:
490     //! \copydoc FileIOError::FileIOError()
SimulationInstabilityError(const ExceptionInitializer & details)491     explicit SimulationInstabilityError(const ExceptionInitializer& details) :
492         GromacsException(details)
493     {
494     }
495 
496     int errorCode() const override;
497 };
498 
499 /*! \brief
500  * Exception class for internal errors.
501  *
502  * \inpublicapi
503  */
504 class InternalError : public GromacsException
505 {
506 public:
507     //! \copydoc FileIOError::FileIOError()
InternalError(const ExceptionInitializer & details)508     explicit InternalError(const ExceptionInitializer& details) : GromacsException(details) {}
509 
510     int errorCode() const override;
511 };
512 
513 /*! \brief
514  * Exception class for incorrect use of an API.
515  *
516  * \inpublicapi
517  */
518 class APIError : public GromacsException
519 {
520 public:
521     //! \copydoc FileIOError::FileIOError()
APIError(const ExceptionInitializer & details)522     explicit APIError(const ExceptionInitializer& details) : GromacsException(details) {}
523 
524     int errorCode() const override;
525 };
526 
527 /*! \brief
528  * Exception class for out-of-range values or indices
529  *
530  * \inpublicapi
531  */
532 class RangeError : public GromacsException
533 {
534 public:
535     //! \copydoc FileIOError::FileIOError()
RangeError(const ExceptionInitializer & details)536     explicit RangeError(const ExceptionInitializer& details) : GromacsException(details) {}
537 
538     int errorCode() const override;
539 };
540 
541 /*! \brief
542  * Exception class for use of an unimplemented feature.
543  *
544  * \inpublicapi
545  */
546 class NotImplementedError : public APIError
547 {
548 public:
549     //! \copydoc FileIOError::FileIOError()
NotImplementedError(const ExceptionInitializer & details)550     explicit NotImplementedError(const ExceptionInitializer& details) : APIError(details) {}
551 
552     int errorCode() const override;
553 };
554 
555 /*! \brief Exception class for use when ensuring that MPI ranks to throw
556  * in a coordinated fashion.
557  *
558  * Generally all ranks that can throw would need to check for whether
559  * an exception has been caught, communicate whether any rank caught,
560  * then all throw one of these, with either a string that describes
561  * any exception caught on that rank, or a generic string.
562  *
563  * \inpublicapi
564  */
565 class ParallelConsistencyError : public APIError
566 {
567 public:
568     //! \copydoc FileIOError::FileIOError()
ParallelConsistencyError(const ExceptionInitializer & details)569     explicit ParallelConsistencyError(const ExceptionInitializer& details) : APIError(details) {}
570 
571     int errorCode() const override;
572 };
573 
574 /*! \brief
575  * Exception class for modular simulator.
576  *
577  * \inpublicapi
578  */
579 class ModularSimulatorError : public GromacsException
580 {
581 public:
582     //! \copydoc FileIOError::FileIOError()
ModularSimulatorError(const ExceptionInitializer & details)583     explicit ModularSimulatorError(const ExceptionInitializer& details) : GromacsException(details)
584     {
585     }
586 
587     [[nodiscard]] int errorCode() const override;
588 };
589 
590 /*! \brief
591  * Macro for throwing an exception.
592  *
593  * \param[in] e    Exception object to throw.
594  *
595  * Using this macro instead of \c throw directly makes it possible to uniformly
596  * attach information into the exception objects.
597  * \p e should evaluate to an instance of an object derived from
598  * GromacsException.
599  *
600  * Basic usage:
601  * \code
602    if (value < 0)
603    {
604        GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
605    }
606    \endcode
607  */
608 #define GMX_THROW(e) \
609     throw(e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
610 
611 /*! \brief
612  * Macro for throwing an exception based on errno.
613  *
614  * \param[in] e       Exception object to throw.
615  * \param[in] syscall Name of the syscall that returned the error.
616  * \param[in] err     errno value returned by the syscall.
617  *
618  * This macro provides a convenience interface for throwing an exception to
619  * report an error based on a errno value.  In addition to adding the necessary
620  * information to the exception object, the macro also ensures that \p errno is
621  * evaluated before, e.g., the constructor of \p e may call other functions
622  * that could overwrite the errno value.
623  * \p e should evaluate to an instance of an object derived from
624  * GromacsException.
625  *
626  * Typical usage (note that gmx::File wraps this particular case):
627  * \code
628    FILE *fp = fopen("filename.txt", "r");
629    if (fp == NULL)
630    {
631        GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
632    }
633    \endcode
634  */
635 #define GMX_THROW_WITH_ERRNO(e, syscall, err)                     \
636     do                                                            \
637     {                                                             \
638         int stored_errno_ = (err);                                \
639         GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_)   \
640                       << gmx::ExceptionInfoApiFunction(syscall)); \
641     } while (0)
642 // TODO: Add an equivalent macro for Windows GetLastError
643 
644 /*! \brief
645  * Formats a standard fatal error message for reporting an exception.
646  *
647  * \param[in] fp  %File to format the message to.
648  * \param[in] ex  Exception to format.
649  *
650  * Does not throw.  If memory allocation fails or some other error occurs
651  * while formatting the error, tries to print a reasonable alternative message.
652  *
653  * Normal usage in Gromacs command-line programs is like this:
654  * \code
655    int main(int argc, char *argv[])
656    {
657        gmx::init(&argc, &argv);
658        try
659        {
660            // The actual code for the program
661            return 0;
662        }
663        catch (const std::exception &ex)
664        {
665            gmx::printFatalErrorMessage(stderr, ex);
666            return gmx::processExceptionAtExit(ex);
667        }
668    }
669    \endcode
670  */
671 void printFatalErrorMessage(FILE* fp, const std::exception& ex);
672 /*! \brief
673  * Formats an error message for reporting an exception.
674  *
675  * \param[in] ex  Exception to format.
676  * \returns   Formatted string containing details of \p ex.
677  * \throws    std::bad_alloc if out of memory.
678  */
679 std::string formatExceptionMessageToString(const std::exception& ex);
680 /*! \brief
681  * Formats an error message for reporting an exception.
682  *
683  * \param     fp  %File to write the message to.
684  * \param[in] ex  Exception to format.
685  * \throws    std::bad_alloc if out of memory.
686  */
687 void formatExceptionMessageToFile(FILE* fp, const std::exception& ex);
688 /*! \brief
689  * Formats an error message for reporting an exception.
690  *
691  * \param     writer  Writer to use for writing the message.
692  * \param[in] ex      Exception to format.
693  * \throws    std::bad_alloc if out of memory.
694  */
695 void formatExceptionMessageToWriter(TextWriter* writer, const std::exception& ex);
696 /*! \brief
697  * Handles an exception that is causing the program to terminate.
698  *
699  * \param[in] ex  Exception that is the cause for terminating the program.
700  * \returns   Return code to return from main().
701  *
702  * This method should be called as the last thing before terminating the
703  * program because of an exception.  It exists to terminate the program as
704  * gracefully as possible in the case of MPI processing (but the current
705  * implementation always calls MPI_Abort()).
706  *
707  * See printFatalErrorMessage() for example usage.
708  *
709  * Does not throw.
710  */
711 int processExceptionAtExit(const std::exception& ex);
712 
713 /*! \brief
714  * Helper function for terminating the program on an exception.
715  *
716  * \param[in] ex  Exception that is the cause for terminating the program.
717  *
718  * Does not throw, and does not return.
719  */
720 [[noreturn]] void processExceptionAsFatalError(const std::exception& ex);
721 
722 /*! \brief
723  * Macro for catching exceptions at C++ -> C boundary.
724  *
725  * This macro is intended for uniform handling of exceptions when C++ code is
726  * called from C code within Gromacs.  Since most existing code is written
727  * using the assumption that fatal errors terminate the program, this macro
728  * implements this behavior for exceptions.  It should only be used in cases
729  * where the error cannot be propagated upwards using return values or such.
730  *
731  * Having this as a macro instead of having the same code in each place makes
732  * it easy to 1) find all such locations in the code, and 2) change the exact
733  * behavior if needed.
734  *
735  * Usage:
736    \code
737    try
738    {
739        // C++ code
740    }
741    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
742    \endcode
743  */
744 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
745     catch (const std::exception& ex) { ::gmx::processExceptionAsFatalError(ex); }
746 
747 //! \}
748 
749 } // namespace gmx
750 
751 #endif
752