EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / include / eina_safety_checks.h
1 /* EINA - EFL data type library
2  * Copyright (C) 2008 Gustavo Sverzut Barbieri
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifndef EINA_SAFETY_CHECKS_H_
20 #define EINA_SAFETY_CHECKS_H_
21
22 /**
23  * @addtogroup Eina_Tools_Group Tools
24  *
25  * @{
26  */
27
28 /**
29  * @defgroup Eina_Safety_Checks_Group Safety Checks
30  *
31  * @warning @c eina_safety_checks.h should only be included by source
32  *          files, after all other includes and before the source file
33  *          specific includes. By source file specific includes we
34  *          mean those that define the functions that are being
35  *          checked. The reason for such complexity is the trick to
36  *          avoid compiler optimizations. If compilers are told that
37  *          some given function will never receive @c NULL
38  *          (EINA_ARG_NONNULL(), then compiler will emit a warning if
39  *          it detects so (good!) but will remove any checks for that
40  *          condition as it believes it will never happen, removing
41  *          all safety checks! By including @c eina_safety_checks.h it
42  *          will redefine EINA_ARG_NONNULL() to void and compiler
43  *          warning will not be emitted, but checks will be there. The
44  *          files already processed with the old macro
45  *          EINA_ARG_NONNULL() will still work and emit the warnings.
46  *
47  *
48  * @code
49  *
50  * // all these files will emit warning from EINA_ARG_NONNULL()
51  * #include <Evas.h>  // third party headers
52  * #include <Ecore.h>
53  * #include <eina_error.h> // eina own header
54  *
55  * #include <eina_safety_checks.h>
56  * // all these files below will NOT emit warning from EINA_ARG_NONNULL(),
57  * // but this is required to have the functions defined there to be checked
58  * // for NULL pointers
59  * #include "my_functions1.h"
60  * #include "my_functions2.h"
61  *
62  * @endcode
63  */
64
65 /**
66  * @addtogroup Eina_Safety_Checks_Group Safety Checks
67  *
68  * Safety checks are a set of macros to check for parameters or values
69  * that should never happen, it is similar in concept to assert(), but
70  * will log and return instead of abort() your program.
71  *
72  * Since these cases should never happen, one may wantto keep safety
73  * checks enabled during tests but disable then during deploy, not
74  * doing any checks at all. This is a common requirement for embedded
75  * systems. Whenever to check or not should be set during compile time
76  * by using @c --disable-safety-checks or @c --enable-safety-checks
77  * options to @c configure script.
78  *
79  * Whenever these macros capture an error, EINA_LOG_ERR() will be
80  * called and @c eina_error set to @c EINA_ERROR_SAFETY_FAILED and can
81  * be checked with eina_error_get() after call.
82  *
83  * @see EINA_SAFETY_ON_NULL_RETURN(), EINA_SAFETY_ON_NULL_RETURN_VAL()
84  *      and other macros.
85  *
86  * @{
87  */
88
89 #include "eina_config.h"
90 #include "eina_error.h"
91
92 /**
93  * @var EINA_ERROR_SAFETY_FAILED
94  * Error identifier corresponding to safety check failure.
95  */
96 EAPI extern Eina_Error EINA_ERROR_SAFETY_FAILED;
97
98 #ifdef EINA_SAFETY_CHECKS
99
100 #include "eina_log.h"
101
102 #define EINA_SAFETY_ON_NULL_RETURN(exp)                                   \
103   do                                                                      \
104     {                                                                     \
105        if (EINA_UNLIKELY((exp) == NULL))                                  \
106          {                                                                \
107             eina_error_set(EINA_ERROR_SAFETY_FAILED);                     \
108             EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
109             return;                                                       \
110          }                                                                \
111     }                                                                     \
112   while (0)
113
114 #define EINA_SAFETY_ON_NULL_RETURN_VAL(exp, val)                          \
115   do                                                                      \
116     {                                                                     \
117        if (EINA_UNLIKELY((exp) == NULL))                                  \
118          {                                                                \
119             eina_error_set(EINA_ERROR_SAFETY_FAILED);                     \
120             EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
121             return (val);                                                 \
122          }                                                                \
123     }                                                                     \
124   while (0)
125
126 #define EINA_SAFETY_ON_NULL_GOTO(exp, label)                              \
127   do                                                                      \
128     {                                                                     \
129        if (EINA_UNLIKELY((exp) == NULL))                                  \
130          {                                                                \
131             eina_error_set(EINA_ERROR_SAFETY_FAILED);                     \
132             EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
133             goto label;                                                   \
134          }                                                                \
135     }                                                                     \
136   while (0)
137
138 #define EINA_SAFETY_ON_TRUE_RETURN(exp)                                   \
139   do                                                                      \
140     {                                                                     \
141        if (EINA_UNLIKELY(exp))                                            \
142          {                                                                \
143             eina_error_set(EINA_ERROR_SAFETY_FAILED);                     \
144             EINA_LOG_ERR("%s", "safety check failed: " # exp " is true"); \
145             return;                                                       \
146          }                                                                \
147     }                                                                     \
148   while (0)
149
150 #define EINA_SAFETY_ON_TRUE_RETURN_VAL(exp, val)                          \
151   do                                                                      \
152     {                                                                     \
153        if (EINA_UNLIKELY(exp))                                            \
154          {                                                                \
155             eina_error_set(EINA_ERROR_SAFETY_FAILED);                     \
156             EINA_LOG_ERR("%s", "safety check failed: " # exp " is true"); \
157             return val;                                                   \
158          }                                                                \
159     }                                                                     \
160   while (0)
161
162 #define EINA_SAFETY_ON_TRUE_GOTO(exp, label)                              \
163   do                                                                      \
164     {                                                                     \
165        if (EINA_UNLIKELY(exp))                                            \
166          {                                                                \
167             eina_error_set(EINA_ERROR_SAFETY_FAILED);                     \
168             EINA_LOG_ERR("%s", "safety check failed: " # exp " is true"); \
169             goto label;                                                   \
170          }                                                                \
171     }                                                                     \
172   while (0)
173
174 #define EINA_SAFETY_ON_FALSE_RETURN(exp)                                   \
175   do                                                                       \
176     {                                                                      \
177        if (EINA_UNLIKELY(!(exp)))                                          \
178          {                                                                 \
179             eina_error_set(EINA_ERROR_SAFETY_FAILED);                      \
180             EINA_LOG_ERR("%s", "safety check failed: " # exp " is false"); \
181             return;                                                        \
182          }                                                                 \
183     }                                                                      \
184   while (0)
185
186 #define EINA_SAFETY_ON_FALSE_RETURN_VAL(exp, val)                          \
187   do                                                                       \
188     {                                                                      \
189        if (EINA_UNLIKELY(!(exp)))                                          \
190          {                                                                 \
191             eina_error_set(EINA_ERROR_SAFETY_FAILED);                      \
192             EINA_LOG_ERR("%s", "safety check failed: " # exp " is false"); \
193             return val;                                                    \
194          }                                                                 \
195     }                                                                      \
196   while (0)
197
198 #define EINA_SAFETY_ON_FALSE_GOTO(exp, label)                              \
199   do                                                                       \
200     {                                                                      \
201        if (EINA_UNLIKELY(!(exp)))                                          \
202          {                                                                 \
203             eina_error_set(EINA_ERROR_SAFETY_FAILED);                      \
204             EINA_LOG_ERR("%s", "safety check failed: " # exp " is false"); \
205             goto label;                                                    \
206          }                                                                 \
207     }                                                                      \
208   while (0)
209
210 #ifdef EINA_ARG_NONNULL
211 /* make EINA_ARG_NONNULL void so GCC does not optimize safety checks */
212 #undef EINA_ARG_NONNULL
213 #define EINA_ARG_NONNULL(...)
214 #endif
215
216 #else /* no safety checks */
217
218 /**
219  * @def EINA_SAFETY_ON_NULL_RETURN
220  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
221  * @param exp The expression to be evaluated.
222  */
223 #define EINA_SAFETY_ON_NULL_RETURN(exp) \
224   do { (void)(!(exp)); } while (0)
225 /**
226  * @def EINA_SAFETY_ON_NULL_RETURN_VAL
227  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
228  * @param exp The expression to be evaluated.
229  * @param val The value to be returned.
230  */
231 #define EINA_SAFETY_ON_NULL_RETURN_VAL(exp, val) \
232   do { if (0 && !(exp)) { (void)val; } } while (0)
233 /**
234  * @def EINA_SAFETY_ON_NULL_GOTO
235  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
236  * @param exp The expression to be evaluated.
237  * @param label The label to jump to.
238  */
239 #define EINA_SAFETY_ON_NULL_GOTO(exp, label) \
240   do { if (0 && (exp) == NULL) { goto label; } } while (0)
241 /**
242  * @def EINA_SAFETY_ON_TRUE_RETURN
243  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
244  * @param exp The expression to be evaluated.
245  */
246 #define EINA_SAFETY_ON_TRUE_RETURN(exp) \
247   do { (void)(exp); } while (0)
248 /**
249  * @def EINA_SAFETY_ON_TRUE_RETURN_VAL
250  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
251  * @param exp The expression to be evaluated.
252  * @param val The value to be returned.
253  */
254 #define EINA_SAFETY_ON_TRUE_RETURN_VAL(exp, val) \
255   do { if (0 && (exp)) { (void)val; } } while (0)
256 /**
257  * @def EINA_SAFETY_ON_TRUE_GOTO
258  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
259  * @param exp The expression to be evaluated.
260  * @param label The label to jump to.
261  */
262 #define EINA_SAFETY_ON_TRUE_GOTO(exp, label) \
263   do { if (0 && (exp)) { goto label; } } while (0)
264 /**
265  * @def EINA_SAFETY_ON_FALSE_RETURN
266  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
267  * @param exp The expression to be evaluated.
268  */
269 #define EINA_SAFETY_ON_FALSE_RETURN(exp) \
270   do { (void)(!(exp)); } while (0)
271 /**
272  * @def EINA_SAFETY_ON_FALSE_RETURN_VAL
273  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
274  * @param exp The expression to be evaluated.
275  * @param val The value to be returned.
276  */
277 #define EINA_SAFETY_ON_FALSE_RETURN_VAL(exp, val) \
278   do { if (0 && !(exp)) { (void)val; } } while (0)
279 /**
280  * @def EINA_SAFETY_ON_FALSE_GOTO
281  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
282  * @param exp The expression to be evaluated.
283  * @param label The label to jump to.
284  */
285 #define EINA_SAFETY_ON_FALSE_GOTO(exp, label) \
286   do { if (0 && !(exp)) { goto label; } } while (0)
287
288 #endif /* safety checks macros */
289 #endif /* EINA_SAFETY_CHECKS_H_ */
290
291 /**
292  * @}
293  */
294
295 /**
296  * @}
297  */