fd66bdb98870ca2fafa92a5fcd9ab49257cd6726
[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, 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/current_function.h"
63 #include "gromacs/utility/gmxassert.h"
64
65 namespace gmx
66 {
67
68 class TextWriter;
69
70 namespace internal
71 {
72 //! Internal container type for storing a list of nested exceptions.
73 typedef std::vector<std::exception_ptr> NestedExceptionList;
74
75 /*! \internal
76  * \brief
77  * Base class for ExceptionInfo.
78  *
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.
82  *
83  * \ingroup module_utility
84  */
85 class IExceptionInfo
86 {
87     public:
88         virtual ~IExceptionInfo();
89         GMX_DEFAULT_CONSTRUCTORS(IExceptionInfo);
90 };
91
92 //! Smart pointer to manage IExceptionInfo ownership.
93 typedef std::unique_ptr<IExceptionInfo> ExceptionInfoPointer;
94
95 class ExceptionData;
96
97 }   // namespace internal
98
99 //! \addtogroup module_utility
100 //! \{
101
102 /*! \brief
103  * Stores additional context information for exceptions.
104  *
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.
110  *
111  * Example of declaring a new info type that stores an integer:
112  * \code
113    typedef ExceptionInfo<struct ExceptionInfoMyInfo_, int> ExceptionInfoMyInfo;
114    \endcode
115  *
116  * \inpublicapi
117  */
118 template <class Tag, typename T>
119 class ExceptionInfo : public internal::IExceptionInfo
120 {
121     public:
122         //! The type of value stored in this object.
123         typedef T value_type;
124
125         //! Creates an info object from given value.
126         explicit ExceptionInfo(const T &value)
127             : value_(value)
128         {
129         }
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)
146         : func(func), file(file), line(line)
147     {
148     }
149
150     //! Function where the throw occurred.
151     const char *func;
152     //! File where the throw occurred.
153     const char *file;
154     //! Line number where the throw occurred.
155     int         line;
156 };
157
158 //! Stores `errno` value that triggered the exception.
159 typedef ExceptionInfo<struct ExceptionInfoErrno_, int>
160     ExceptionInfoErrno;
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;
167
168 /*! \brief
169  * Provides information for Gromacs exception constructors.
170  *
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.
178  *
179  * \todo
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.
188  *
189  * \ingroup module_utility
190  */
191 class ExceptionInitializer
192 {
193     public:
194         /*! \brief
195          * Creates an initialized with the given string as the reason.
196          *
197          * \param[in] reason  Detailed reason for the exception.
198          * \throw     std::bad_alloc if out of memory.
199          *
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.
203          */
204         ExceptionInitializer(const char *reason)
205             : reason_(reason)
206         {
207         }
208         //! \copydoc ExceptionInitializer(const char *)
209         ExceptionInitializer(const std::string &reason)
210             : reason_(reason)
211         {
212         }
213
214         /*! \brief
215          * Returns true if addCurrentExceptionAsNested() has been called.
216          *
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.
220          */
221         bool hasNestedExceptions() const { return !nested_.empty(); }
222         /*! \brief
223          * Adds the currently caught exception as a nested exception.
224          *
225          * May be called multiple times; all provided exceptions will be added
226          * in a list of nested exceptions.
227          *
228          * Must not be called outside a catch block.
229          */
230         void addCurrentExceptionAsNested()
231         {
232             nested_.push_back(std::current_exception());
233         }
234         /*! \brief
235          * Adds the specified exception as a nested exception.
236          *
237          * May be called multiple times; all provided exceptions will be added
238          * in a list of nested exceptions.
239          *
240          * This is equivalent to throwing \p ex and calling
241          * addCurrentExceptionAsNested() in the catch block, but potentially
242          * more efficient.
243          */
244         template <class Exception>
245         void addNested(const Exception &ex)
246         {
247             nested_.push_back(std::make_exception_ptr(ex));
248         }
249
250     private:
251         std::string                     reason_;
252         internal::NestedExceptionList   nested_;
253
254         friend class GromacsException;
255 };
256
257 /*! \brief
258  * Base class for all exception objects in Gromacs.
259  *
260  * \inpublicapi
261  */
262 class GromacsException : public std::exception
263 {
264     public:
265         // Explicitly declared because some compiler/library combinations warn
266         // about missing noexcept otherwise.
267         virtual ~GromacsException() noexcept {}
268
269         GMX_DEFAULT_CONSTRUCTORS(GromacsException);
270
271         /*! \brief
272          * Returns the reason string for the exception.
273          *
274          * The return value is the string that was passed to the constructor.
275          */
276         virtual const char *what() const noexcept;
277         /*! \brief
278          * Returns the error code corresponding to the exception type.
279          */
280         virtual int errorCode() const = 0;
281
282         /*! \brief
283          * Returns the value associated with given ExceptionInfo.
284          *
285          * \tparam  InfoType  ExceptionInfo type to get the value for.
286          * \returns Value set for `InfoType`, or `nullptr` if such info has not
287          *     been set.
288          *
289          * Does not throw.
290          */
291         template <class InfoType>
292         const typename InfoType::value_type *getInfo() const
293         {
294             const internal::IExceptionInfo *item = getInfo(typeid(InfoType));
295             if (item != nullptr)
296             {
297                 GMX_ASSERT(dynamic_cast<const InfoType *>(item) != nullptr,
298                            "Invalid exception info item found");
299                 return &static_cast<const InfoType *>(item)->value();
300             }
301             return nullptr;
302         }
303
304         /*! \brief
305          * Associates extra information with the exception.
306          *
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.
312          *
313          * If an item of this type is already associated, it is overwritten.
314          */
315         template <class Tag, typename T>
316         void setInfo(const ExceptionInfo<Tag, T> &item)
317         {
318             typedef ExceptionInfo<Tag, T> ItemType;
319             internal::ExceptionInfoPointer itemPtr(new ItemType(item));
320             setInfo(typeid(ItemType), std::move(itemPtr));
321         }
322
323         /*! \brief
324          * Adds context information to this exception.
325          *
326          * \param[in] context  Context string to add.
327          * \throws    std::bad_alloc if out of memory.
328          *
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
331          * exception.
332          *
333          * \todo
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
338          * discussion.
339          */
340         void prependContext(const std::string &context);
341
342     protected:
343         /*! \brief
344          * Creates an exception object with the provided initializer/reason.
345          *
346          * \param[in] details  Initializer for the exception.
347          * \throws    std::bad_alloc if out of memory.
348          */
349         explicit GromacsException(const ExceptionInitializer &details);
350
351     private:
352         const internal::IExceptionInfo *getInfo(const std::type_index &index) const;
353         void setInfo(const std::type_index &index, internal::ExceptionInfoPointer &&item);
354
355         std::shared_ptr<internal::ExceptionData> data_;
356 };
357
358 /*! \brief
359  * Associates extra information with an exception.
360  *
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.
366  *
367  * \internal
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.
380  *
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.
385  */
386 template <class Exception, class Tag, class T>
387 inline
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)
390 {
391     const_cast<Exception &>(ex).setInfo(item);
392     return ex;
393 }
394
395 /*! \brief
396  * Exception class for file I/O errors.
397  *
398  * \inpublicapi
399  */
400 class FileIOError : public GromacsException
401 {
402     public:
403         /*! \brief
404          * Creates an exception object with the provided initializer/reason.
405          *
406          * \param[in] details  Initializer for the exception.
407          * \throws    std::bad_alloc if out of memory.
408          *
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.
412          */
413         explicit FileIOError(const ExceptionInitializer &details)
414             : GromacsException(details) {}
415
416         virtual int errorCode() const;
417 };
418
419 /*! \brief
420  * Exception class for user input errors.
421  *
422  * Derived classes should be used to indicate the nature of the error instead
423  * of throwing this class directly.
424  *
425  * \inpublicapi
426  */
427 class UserInputError : public GromacsException
428 {
429     protected:
430         //! \copydoc FileIOError::FileIOError()
431         explicit UserInputError(const ExceptionInitializer &details)
432             : GromacsException(details) {}
433 };
434
435 /*! \brief
436  * Exception class for situations where user input cannot be parsed/understood.
437  *
438  * \inpublicapi
439  */
440 class InvalidInputError : public UserInputError
441 {
442     public:
443         //! \copydoc FileIOError::FileIOError()
444         explicit InvalidInputError(const ExceptionInitializer &details)
445             : UserInputError(details) {}
446
447         virtual int errorCode() const;
448 };
449
450 /*! \brief
451  * Exception class for situations where user input is inconsistent.
452  *
453  * \inpublicapi
454  */
455 class InconsistentInputError : public UserInputError
456 {
457     public:
458         //! \copydoc FileIOError::FileIOError()
459         explicit InconsistentInputError(const ExceptionInitializer &details)
460             : UserInputError(details) {}
461
462         virtual int errorCode() const;
463 };
464
465 /*! \brief
466  * Exception class when a specified tolerance cannot be achieved.
467  *
468  * \inpublicapi
469  */
470 class ToleranceError : public GromacsException
471 {
472     public:
473         /*! \brief
474          * Creates an exception object with the provided initializer/reason.
475          *
476          * \param[in] details  Initializer for the exception.
477          * \throws    std::bad_alloc if out of memory.
478          *
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.
482          */
483         explicit ToleranceError(const ExceptionInitializer &details)
484             : GromacsException(details) {}
485
486         virtual int errorCode() const;
487 };
488
489 /*! \brief
490  * Exception class for simulation instabilities.
491  *
492  * \inpublicapi
493  */
494 class SimulationInstabilityError : public GromacsException
495 {
496     public:
497         //! \copydoc FileIOError::FileIOError()
498         explicit SimulationInstabilityError(const ExceptionInitializer &details)
499             : GromacsException(details) {}
500
501         virtual int errorCode() const;
502 };
503
504 /*! \brief
505  * Exception class for internal errors.
506  *
507  * \inpublicapi
508  */
509 class InternalError : public GromacsException
510 {
511     public:
512         //! \copydoc FileIOError::FileIOError()
513         explicit InternalError(const ExceptionInitializer &details)
514             : GromacsException(details) {}
515
516         virtual int errorCode() const;
517 };
518
519 /*! \brief
520  * Exception class for incorrect use of an API.
521  *
522  * \inpublicapi
523  */
524 class APIError : public GromacsException
525 {
526     public:
527         //! \copydoc FileIOError::FileIOError()
528         explicit APIError(const ExceptionInitializer &details)
529             : GromacsException(details) {}
530
531         virtual int errorCode() const;
532 };
533
534 /*! \brief
535  * Exception class for out-of-range values or indices
536  *
537  * \inpublicapi
538  */
539 class RangeError : public GromacsException
540 {
541     public:
542         //! \copydoc FileIOError::FileIOError()
543         explicit RangeError(const ExceptionInitializer &details)
544             : GromacsException(details) {}
545
546         virtual int errorCode() const;
547 };
548
549 /*! \brief
550  * Exception class for use of an unimplemented feature.
551  *
552  * \inpublicapi
553  */
554 class NotImplementedError : public APIError
555 {
556     public:
557         //! \copydoc FileIOError::FileIOError()
558         explicit NotImplementedError(const ExceptionInitializer &details)
559             : APIError(details) {}
560
561         virtual int errorCode() const;
562 };
563
564 /*! \brief
565  * Macro for throwing an exception.
566  *
567  * \param[in] e    Exception object to throw.
568  *
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
572  * GromacsException.
573  *
574  * Basic usage:
575  * \code
576    if (value < 0)
577    {
578        GMX_THROW(InconsistentUserInput("Negative values not allowed for value"));
579    }
580    \endcode
581  */
582 #define GMX_THROW(e) \
583     throw (e) << gmx::ExceptionInfoLocation(gmx::ThrowLocation(GMX_CURRENT_FUNCTION, __FILE__, __LINE__))
584
585 /*! \brief
586  * Macro for throwing an exception based on errno.
587  *
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.
591  *
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
598  * GromacsException.
599  *
600  * Typical usage (note that gmx::File wraps this particular case):
601  * \code
602    FILE *fp = fopen("filename.txt", "r");
603    if (fp == NULL)
604    {
605        GMX_THROW(FileIOError("Could not open file"), "fopen", errno);
606    }
607    \endcode
608  */
609 #define GMX_THROW_WITH_ERRNO(e, syscall, err) \
610     do { \
611         int stored_errno_ = (err); \
612         GMX_THROW((e) << gmx::ExceptionInfoErrno(stored_errno_) \
613                   << gmx::ExceptionInfoApiFunction(syscall)); \
614     } while (0)
615 //TODO: Add an equivalent macro for Windows GetLastError
616
617 /*! \brief
618  * Formats a standard fatal error message for reporting an exception.
619  *
620  * \param[in] fp  %File to format the message to.
621  * \param[in] ex  Exception to format.
622  *
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.
625  *
626  * Normal usage in Gromacs command-line programs is like this:
627  * \code
628    int main(int argc, char *argv[])
629    {
630        gmx::init(&argc, &argv);
631        try
632        {
633            // The actual code for the program
634            return 0;
635        }
636        catch (const std::exception &ex)
637        {
638            gmx::printFatalErrorMessage(stderr, ex);
639            return gmx::processExceptionAtExit(ex);
640        }
641    }
642    \endcode
643  */
644 void printFatalErrorMessage(FILE *fp, const std::exception &ex);
645 /*! \brief
646  * Formats an error message for reporting an exception.
647  *
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.
651  */
652 std::string formatExceptionMessageToString(const std::exception &ex);
653 /*! \brief
654  * Formats an error message for reporting an exception.
655  *
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.
659  */
660 void formatExceptionMessageToFile(FILE *fp, const std::exception &ex);
661 /*! \brief
662  * Formats an error message for reporting an exception.
663  *
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.
667  */
668 void formatExceptionMessageToWriter(TextWriter           *writer,
669                                     const std::exception &ex);
670 /*! \brief
671  * Handles an exception that is causing the program to terminate.
672  *
673  * \param[in] ex  Exception that is the cause for terminating the program.
674  * \returns   Return code to return from main().
675  *
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()).
680  *
681  * See printFatalErrorMessage() for example usage.
682  *
683  * Does not throw.
684  */
685 int processExceptionAtExit(const std::exception &ex);
686
687 /*! \brief
688  * Helper function for terminating the program on an exception.
689  *
690  * \param[in] ex  Exception that is the cause for terminating the program.
691  *
692  * Does not throw, and does not return.
693  */
694 gmx_noreturn void processExceptionAsFatalError(const std::exception &ex);
695
696 /*! \brief
697  * Macro for catching exceptions at C++ -> C boundary.
698  *
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.
704  *
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.
708  *
709  * Usage:
710    \code
711    try
712    {
713        // C++ code
714    }
715    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
716    \endcode
717  */
718 #define GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR \
719     catch (const std::exception &ex) { \
720         ::gmx::processExceptionAsFatalError(ex); \
721     }
722
723 //! \}
724
725 } // namespace gmx
726
727 #endif