034a60b3d12ec3c37c1d1eeabb895de3290259bd
[alexxy/gromacs.git] / src / gromacs / utility / exceptions.h
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.
129     explicit ExceptionInfo(const T& value) : value_(value) {}
130
131     //! Returns the stored 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.
145     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      */
200     ExceptionInitializer(const char* reason) : reason_(reason) {}
201     //! \copydoc ExceptionInitializer(const char *)
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      */
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      */
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>
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.
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>
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>
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 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)
384 {
385     ex.setInfo(item);
386     return ex;
387 }
388
389 /*! \brief
390  * Exception class for file I/O errors.
391  *
392  * \inpublicapi
393  */
394 class FileIOError : public GromacsException
395 {
396 public:
397     /*! \brief
398      * Creates an exception object with the provided initializer/reason.
399      *
400      * \param[in] details  Initializer for the exception.
401      * \throws    std::bad_alloc if out of memory.
402      *
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.
406      */
407     explicit FileIOError(const ExceptionInitializer& details) : GromacsException(details) {}
408
409     int errorCode() const override;
410 };
411
412 /*! \brief
413  * Exception class for user input errors.
414  *
415  * Derived classes should be used to indicate the nature of the error instead
416  * of throwing this class directly.
417  *
418  * \inpublicapi
419  */
420 class UserInputError : public GromacsException
421 {
422 protected:
423     //! \copydoc FileIOError::FileIOError()
424     explicit UserInputError(const ExceptionInitializer& details) : GromacsException(details) {}
425 };
426
427 /*! \brief
428  * Exception class for situations where user input cannot be parsed/understood.
429  *
430  * \inpublicapi
431  */
432 class InvalidInputError : public UserInputError
433 {
434 public:
435     //! \copydoc FileIOError::FileIOError()
436     explicit InvalidInputError(const ExceptionInitializer& details) : UserInputError(details) {}
437
438     int errorCode() const override;
439 };
440
441 /*! \brief
442  * Exception class for situations where user input is inconsistent.
443  *
444  * \inpublicapi
445  */
446 class InconsistentInputError : public UserInputError
447 {
448 public:
449     //! \copydoc FileIOError::FileIOError()
450     explicit InconsistentInputError(const ExceptionInitializer& details) : UserInputError(details)
451     {
452     }
453
454     int errorCode() const override;
455 };
456
457 /*! \brief
458  * Exception class when a specified tolerance cannot be achieved.
459  *
460  * \inpublicapi
461  */
462 class ToleranceError : public GromacsException
463 {
464 public:
465     /*! \brief
466      * Creates an exception object with the provided initializer/reason.
467      *
468      * \param[in] details  Initializer for the exception.
469      * \throws    std::bad_alloc if out of memory.
470      *
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.
474      */
475     explicit ToleranceError(const ExceptionInitializer& details) : GromacsException(details) {}
476
477     int errorCode() const override;
478 };
479
480 /*! \brief
481  * Exception class for simulation instabilities.
482  *
483  * \inpublicapi
484  */
485 class SimulationInstabilityError : public GromacsException
486 {
487 public:
488     //! \copydoc FileIOError::FileIOError()
489     explicit SimulationInstabilityError(const ExceptionInitializer& details) :
490         GromacsException(details)
491     {
492     }
493
494     int errorCode() const override;
495 };
496
497 /*! \brief
498  * Exception class for internal errors.
499  *
500  * \inpublicapi
501  */
502 class InternalError : public GromacsException
503 {
504 public:
505     //! \copydoc FileIOError::FileIOError()
506     explicit InternalError(const ExceptionInitializer& details) : GromacsException(details) {}
507
508     int errorCode() const override;
509 };
510
511 /*! \brief
512  * Exception class for incorrect use of an API.
513  *
514  * \inpublicapi
515  */
516 class APIError : public GromacsException
517 {
518 public:
519     //! \copydoc FileIOError::FileIOError()
520     explicit APIError(const ExceptionInitializer& details) : GromacsException(details) {}
521
522     int errorCode() const override;
523 };
524
525 /*! \brief
526  * Exception class for out-of-range values or indices
527  *
528  * \inpublicapi
529  */
530 class RangeError : public GromacsException
531 {
532 public:
533     //! \copydoc FileIOError::FileIOError()
534     explicit RangeError(const ExceptionInitializer& details) : GromacsException(details) {}
535
536     int errorCode() const override;
537 };
538
539 /*! \brief
540  * Exception class for use of an unimplemented feature.
541  *
542  * \inpublicapi
543  */
544 class NotImplementedError : public APIError
545 {
546 public:
547     //! \copydoc FileIOError::FileIOError()
548     explicit NotImplementedError(const ExceptionInitializer& details) : APIError(details) {}
549
550     int errorCode() const override;
551 };
552
553 /*! \brief Exception class for use when ensuring that MPI ranks to throw
554  * in a coordinated fashion.
555  *
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.
560  *
561  * \inpublicapi
562  */
563 class ParallelConsistencyError : public APIError
564 {
565 public:
566     //! \copydoc FileIOError::FileIOError()
567     explicit ParallelConsistencyError(const ExceptionInitializer& details) : APIError(details) {}
568
569     int errorCode() const override;
570 };
571
572 /*! \brief
573  * Macro for throwing an exception.
574  *
575  * \param[in] e    Exception object to throw.
576  *
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
580  * GromacsException.
581  *
582  * Basic usage:
583  * \code
584    if (value < 0)
585    {
586        GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
587    }
588    \endcode
589  */
590 #define GMX_THROW(e) \
591     throw(e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
592
593 /*! \brief
594  * Macro for throwing an exception based on errno.
595  *
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.
599  *
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
606  * GromacsException.
607  *
608  * Typical usage (note that gmx::File wraps this particular case):
609  * \code
610    FILE *fp = fopen("filename.txt", "r");
611    if (fp == NULL)
612    {
613        GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
614    }
615    \endcode
616  */
617 #define GMX_THROW_WITH_ERRNO(e, syscall, err)                     \
618     do                                                            \
619     {                                                             \
620         int stored_errno_ = (err);                                \
621         GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_)   \
622                       << gmx::ExceptionInfoApiFunction(syscall)); \
623     } while (0)
624 // TODO: Add an equivalent macro for Windows GetLastError
625
626 /*! \brief
627  * Formats a standard fatal error message for reporting an exception.
628  *
629  * \param[in] fp  %File to format the message to.
630  * \param[in] ex  Exception to format.
631  *
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.
634  *
635  * Normal usage in Gromacs command-line programs is like this:
636  * \code
637    int main(int argc, char *argv[])
638    {
639        gmx::init(&argc, &argv);
640        try
641        {
642            // The actual code for the program
643            return 0;
644        }
645        catch (const std::exception &ex)
646        {
647            gmx::printFatalErrorMessage(stderr, ex);
648            return gmx::processExceptionAtExit(ex);
649        }
650    }
651    \endcode
652  */
653 void printFatalErrorMessage(FILE* fp, const std::exception& ex);
654 /*! \brief
655  * Formats an error message for reporting an exception.
656  *
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.
660  */
661 std::string formatExceptionMessageToString(const std::exception& ex);
662 /*! \brief
663  * Formats an error message for reporting an exception.
664  *
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.
668  */
669 void formatExceptionMessageToFile(FILE* fp, const std::exception& ex);
670 /*! \brief
671  * Formats an error message for reporting an exception.
672  *
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.
676  */
677 void formatExceptionMessageToWriter(TextWriter* writer, const std::exception& ex);
678 /*! \brief
679  * Handles an exception that is causing the program to terminate.
680  *
681  * \param[in] ex  Exception that is the cause for terminating the program.
682  * \returns   Return code to return from main().
683  *
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()).
688  *
689  * See printFatalErrorMessage() for example usage.
690  *
691  * Does not throw.
692  */
693 int processExceptionAtExit(const std::exception& ex);
694
695 /*! \brief
696  * Helper function for terminating the program on an exception.
697  *
698  * \param[in] ex  Exception that is the cause for terminating the program.
699  *
700  * Does not throw, and does not return.
701  */
702 [[noreturn]] void processExceptionAsFatalError(const std::exception& ex);
703
704 /*! \brief
705  * Macro for catching exceptions at C++ -> C boundary.
706  *
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.
712  *
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.
716  *
717  * Usage:
718    \code
719    try
720    {
721        // C++ code
722    }
723    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
724    \endcode
725  */
726 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
727     catch (const std::exception& ex) { ::gmx::processExceptionAsFatalError(ex); }
728
729 //! \}
730
731 } // namespace gmx
732
733 #endif