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