1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the COPYING file, which can be found at the root of the source code       *
9  * distribution tree, or in https://www.hdfgroup.org/licenses.               *
10  * If you do not have access to either file, you may request a copy from     *
11  * help@hdfgroup.org.                                                        *
12  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13 
14 /*
15  *  Header file for error values, etc.
16  */
17 #ifndef H5Eprivate_H
18 #define H5Eprivate_H
19 
20 #include "H5Epublic.h"
21 
22 /* Private headers needed by this file */
23 #include "H5private.h"
24 
25 /* Typedef for error stack (defined in H5Epkg.h) */
26 typedef struct H5E_t H5E_t;
27 
28 /*
29  * HERROR macro, used to facilitate error reporting between a FUNC_ENTER()
30  * and a FUNC_LEAVE() within a function body.  The arguments are the major
31  * error number, the minor error number, and a description of the error.
32  */
33 #define HERROR(maj_id, min_id, ...)                                                                          \
34     H5E_printf_stack(NULL, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, maj_id, min_id, __VA_ARGS__)
35 
36 /*
37  * HCOMMON_ERROR macro, used by HDONE_ERROR and HGOTO_ERROR
38  * (Shouldn't need to be used outside this header file)
39  */
40 #define HCOMMON_ERROR(maj, min, ...)                                                                         \
41     HERROR(maj, min, __VA_ARGS__);                                                                           \
42     err_occurred = TRUE;                                                                                     \
43     err_occurred = err_occurred; /* Shut GCC warnings up! */
44 
45 /*
46  * HDONE_ERROR macro, used to facilitate error reporting between a
47  * FUNC_ENTER() and a FUNC_LEAVE() within a function body, but _AFTER_ the
48  * "done:" label.  The arguments are
49  * the major error number, the minor error number, a return value, and a
50  * description of the error.
51  * (This macro can also be used to push an error and set the return value
52  *      without jumping to any labels)
53  */
54 #define HDONE_ERROR(maj, min, ret_val, ...)                                                                  \
55     {                                                                                                        \
56         HCOMMON_ERROR(maj, min, __VA_ARGS__);                                                                \
57         ret_value = ret_val;                                                                                 \
58     }
59 
60 /*
61  * HGOTO_ERROR macro, used to facilitate error reporting between a
62  * FUNC_ENTER() and a FUNC_LEAVE() within a function body.  The arguments are
63  * the major error number, the minor error number, the return value, and an
64  * error string.  The return value is assigned to a variable `ret_value' and
65  * control branches to the `done' label.
66  */
67 #define HGOTO_ERROR(maj, min, ret_val, ...)                                                                  \
68     {                                                                                                        \
69         HCOMMON_ERROR(maj, min, __VA_ARGS__);                                                                \
70         HGOTO_DONE(ret_val)                                                                                  \
71     }
72 
73 /*
74  * HGOTO_ERROR_TAG macro, used like HGOTO_ERROR between H5_BEGIN_TAG and
75  * H5_END_TAG statements.  Resets the metadata tag before leaving the function.
76  */
77 #define HGOTO_ERROR_TAG(maj, min, ret_val, ...)                                                              \
78     {                                                                                                        \
79         H5AC_tag(prv_tag, NULL);                                                                             \
80         HCOMMON_ERROR(maj, min, __VA_ARGS__);                                                                \
81         HGOTO_DONE(ret_val)                                                                                  \
82     }
83 
84 /*
85  * HGOTO_DONE macro, used to facilitate normal return between a FUNC_ENTER()
86  * and a FUNC_LEAVE() within a function body. The argument is the return
87  * value which is assigned to the `ret_value' variable.	 Control branches to
88  * the `done' label.
89  */
90 #define HGOTO_DONE(ret_val)                                                                                  \
91     {                                                                                                        \
92         ret_value = ret_val;                                                                                 \
93         goto done;                                                                                           \
94     }
95 
96 /*
97  * HGOTO_DONE_TAG macro, used like HGOTO_DONE between H5_BEGIN_TAG and
98  * H5_END_TAG statements.  Resets the metadata tag before leaving the function.
99  */
100 #define HGOTO_DONE_TAG(ret_val)                                                                              \
101     {                                                                                                        \
102         H5AC_tag(prv_tag, NULL);                                                                             \
103         HGOTO_DONE(ret_val)                                                                                  \
104     }
105 
106 /*
107  * Macros handling system error messages as described in C standard.
108  * These macros assume errnum is a valid system error code.
109  */
110 
111 /* Retrieve the error code description string and push it onto the error
112  * stack.
113  */
114 #ifndef H5_HAVE_WIN32_API
115 #define HSYS_DONE_ERROR(majorcode, minorcode, retcode, str)                                                  \
116     {                                                                                                        \
117         int myerrno = errno;                                                                                 \
118         /* Other projects may rely on the description format to get the errno and any changes should be      \
119          * considered as an API change                                                                       \
120          */                                                                                                  \
121         HDONE_ERROR(majorcode, minorcode, retcode, "%s, errno = %d, error message = '%s'", str, myerrno,     \
122                     HDstrerror(myerrno));                                                                    \
123     }
124 #define HSYS_GOTO_ERROR(majorcode, minorcode, retcode, str)                                                  \
125     {                                                                                                        \
126         int myerrno = errno;                                                                                 \
127         /* Other projects may rely on the description format to get the errno and any changes should be      \
128          * considered as an API change                                                                       \
129          */                                                                                                  \
130         HGOTO_ERROR(majorcode, minorcode, retcode, "%s, errno = %d, error message = '%s'", str, myerrno,     \
131                     HDstrerror(myerrno));                                                                    \
132     }
133 #else /* H5_HAVE_WIN32_API */
134 /* On Windows we also emit the result of GetLastError(). This call returns a DWORD, which is always a
135  * 32-bit unsigned type. Note that on Windows, either errno or GetLastError() (but probably not both) will
136  * be useful depending on whether a C/POSIX or Win32 call failed. The other value will likely be zero,
137  * though I wouldn't count on that.
138  */
139 #define HSYS_DONE_ERROR(majorcode, minorcode, retcode, str)                                                  \
140     {                                                                                                        \
141         int   myerrno   = errno;                                                                             \
142         DWORD win_error = GetLastError();                                                                    \
143         /* Other projects may rely on the description format to get the errno and any changes should be      \
144          * considered as an API change                                                                       \
145          */                                                                                                  \
146         HDONE_ERROR(majorcode, minorcode, retcode,                                                           \
147                     "%s, errno = %d, error message = '%s', Win32 GetLastError() = %" PRIu32 "", str,         \
148                     myerrno, HDstrerror(myerrno), win_error);                                                \
149     }
150 #define HSYS_GOTO_ERROR(majorcode, minorcode, retcode, str)                                                  \
151     {                                                                                                        \
152         int   myerrno   = errno;                                                                             \
153         DWORD win_error = GetLastError();                                                                    \
154         /* Other projects may rely on the description format to get the errno and any changes should be      \
155          * considered as an API change                                                                       \
156          */                                                                                                  \
157         HGOTO_ERROR(majorcode, minorcode, retcode,                                                           \
158                     "%s, errno = %d, error message = '%s', Win32 GetLastError() = %" PRIu32 "", str,         \
159                     myerrno, HDstrerror(myerrno), win_error);                                                \
160     }
161 #endif /* H5_HAVE_WIN32_API */
162 
163 #ifdef H5_HAVE_PARALLEL
164 /*
165  * MPI error handling macros.
166  */
167 
168 extern char H5E_mpi_error_str[MPI_MAX_ERROR_STRING];
169 extern int  H5E_mpi_error_str_len;
170 
171 #define HMPI_DONE_ERROR(retcode, str, mpierr)                                                                \
172     {                                                                                                        \
173         MPI_Error_string(mpierr, H5E_mpi_error_str, &H5E_mpi_error_str_len);                                 \
174         HDONE_ERROR(H5E_INTERNAL, H5E_MPI, retcode, "%s: MPI error string is '%s'", str, H5E_mpi_error_str); \
175     }
176 #define HMPI_GOTO_ERROR(retcode, str, mpierr)                                                                \
177     {                                                                                                        \
178         MPI_Error_string(mpierr, H5E_mpi_error_str, &H5E_mpi_error_str_len);                                 \
179         HGOTO_ERROR(H5E_INTERNAL, H5E_MPI, retcode, "%s: MPI error string is '%s'", str, H5E_mpi_error_str); \
180     }
181 #endif /* H5_HAVE_PARALLEL */
182 
183 /******************************************************************************/
184 /* Revisions to Error Macros, to go with Revisions to FUNC_ENTER/LEAVE Macros */
185 /******************************************************************************/
186 
187 /*
188  * H5E_PRINTF macro, used to facilitate error reporting between a BEGIN_FUNC()
189  * and an END_FUNC() within a function body.  The arguments are the minor
190  * error number, a description of the error (as a printf-like format string),
191  * and an optional set of arguments for the printf format arguments.
192  */
193 #define H5E_PRINTF(...)                                                                                      \
194     H5E_printf_stack(NULL, __FILE__, FUNC, __LINE__, H5E_ERR_CLS_g, H5_MY_PKG_ERR, __VA_ARGS__)
195 
196 /*
197  * H5_LEAVE macro, used to facilitate control flow between a
198  * BEGIN_FUNC() and an END_FUNC() within a function body.  The argument is
199  * the return value.
200  * The return value is assigned to a variable `ret_value' and control branches
201  * to the `catch_except' label, if we're not already past it.
202  */
203 #define H5_LEAVE(v)                                                                                          \
204     {                                                                                                        \
205         ret_value = v;                                                                                       \
206         if (!past_catch)                                                                                     \
207             goto catch_except;                                                                               \
208     }
209 
210 /*
211  * H5E_THROW macro, used to facilitate error reporting between a
212  * FUNC_ENTER() and a FUNC_LEAVE() within a function body.  The arguments are
213  * the minor error number, and an error string.
214  * The return value is assigned to a variable `ret_value' and control branches
215  * to the `catch_except' label, if we're not already past it.
216  */
217 #define H5E_THROW(...)                                                                                       \
218     {                                                                                                        \
219         H5E_PRINTF(__VA_ARGS__);                                                                             \
220         H5_LEAVE(fail_value)                                                                                 \
221     }
222 
223 /* Macro for "catching" flow of control when an error occurs.  Note that the
224  *      H5_LEAVE macro won't jump back here once it's past this point.
225  */
226 #define CATCH                                                                                                \
227 catch_except:;                                                                                               \
228     past_catch = TRUE;
229 
230 /* Library-private functions defined in H5E package */
231 H5_DLL herr_t H5E_init(void);
232 H5_DLL herr_t H5E_printf_stack(H5E_t *estack, const char *file, const char *func, unsigned line, hid_t cls_id,
233                                hid_t maj_id, hid_t min_id, const char *fmt, ...) H5_ATTR_FORMAT(printf, 8, 9);
234 H5_DLL herr_t H5E_clear_stack(H5E_t *estack);
235 H5_DLL herr_t H5E_dump_api_stack(hbool_t is_api);
236 
237 #endif /* H5Eprivate_H */
238