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 the compiler will emit a warning if
39  *          it detects so (good!) and also 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 last 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  *
54  * #include <eina_safety_checks.h>
55  * // all the files below will NOT emit warning from EINA_ARG_NONNULL(),
56  * // but this is required to have the functions defined there to be checked
57  * // for NULL pointers
58  * #include "my_functions1.h"
59  * #include "my_functions2.h"
60  *
61  * @endcode
62  */
63 
64 /**
65  * @addtogroup Eina_Safety_Checks_Group Safety Checks
66  *
67  * Safety checks are a set of macros to check for parameters or values
68  * that should never happen, it is similar in concept to assert(), but
69  * will log and return instead of abort() your program.
70  *
71  * Since these cases should never happen, one may want to keep safety
72  * checks enabled during tests but disable them during deploy, not
73  * doing any checks at all. This is a common requirement for embedded
74  * systems. When to check or not should be set during compile time
75  * by using @c --disable-safety-checks or @c --enable-safety-checks
76  * options to @c configure script.
77  *
78  * Whenever these macros capture an error, EINA_LOG_ERR() will be
79  * called.
80  *
81  * @see EINA_SAFETY_ON_NULL_RETURN(), EINA_SAFETY_ON_NULL_RETURN_VAL()
82  *      and other macros.
83  *
84  * @{
85  */
86 
87 #include "eina_config.h"
88 #include "eina_error.h"
89 
90 EAPI extern Eina_Error EINA_ERROR_SAFETY_FAILED;
91 
92 #ifdef EINA_SAFETY_CHECKS
93 
94 #include "eina_log.h"
95 
96 # ifdef EFL_BETA_API_SUPPORT
97 /**
98  * Log entry-point called every time an eina safety check fails.
99  *
100  * One purpose of this dedicated function is to provide a convenient breakpoint
101  * for GDB debugging. Also, this gives it a dedicated log domain, rather than
102  * using the default one.
103  *
104  * @since 1.17
105  * @internal
106  */
107 EAPI void _eina_safety_error(const char *file, const char *func, int line, const char *str);
108 #  define EINA_SAFETY_ERROR(msg) _eina_safety_error(__FILE__, __func__, __LINE__, msg)
109 # else
110 #  define EINA_SAFETY_ERROR(msg) EINA_LOG_ERR("%s", msg)
111 # endif
112 
113 #define EINA_SAFETY_ON_NULL_RETURN(exp)                                   \
114   do                                                                      \
115     {                                                                     \
116        if (EINA_UNLIKELY((exp) == NULL))                                  \
117          {                                                                \
118             EINA_SAFETY_ERROR("safety check failed: " # exp " == NULL");  \
119             return;                                                       \
120          }                                                                \
121     }                                                                     \
122   while (0)
123 
124 #define EINA_SAFETY_ON_NULL_RETURN_VAL(exp, val)                          \
125   do                                                                      \
126     {                                                                     \
127        if (EINA_UNLIKELY((exp) == NULL))                                  \
128          {                                                                \
129             EINA_SAFETY_ERROR("safety check failed: " # exp " == NULL");  \
130             return (val);                                                 \
131          }                                                                \
132     }                                                                     \
133   while (0)
134 
135 #define EINA_SAFETY_ON_NULL_GOTO(exp, label)                              \
136   do                                                                      \
137     {                                                                     \
138        if (EINA_UNLIKELY((exp) == NULL))                                  \
139          {                                                                \
140             EINA_SAFETY_ERROR("safety check failed: " # exp " == NULL");  \
141             goto label;                                                   \
142          }                                                                \
143     }                                                                     \
144   while (0)
145 
146 #define EINA_SAFETY_ON_TRUE_RETURN(exp)                                   \
147   do                                                                      \
148     {                                                                     \
149        if (EINA_UNLIKELY(exp))                                            \
150          {                                                                \
151             EINA_SAFETY_ERROR("safety check failed: " # exp " is true");  \
152             return;                                                       \
153          }                                                                \
154     }                                                                     \
155   while (0)
156 
157 #define EINA_SAFETY_ON_TRUE_RETURN_VAL(exp, val)                          \
158   do                                                                      \
159     {                                                                     \
160        if (EINA_UNLIKELY(exp))                                            \
161          {                                                                \
162             EINA_SAFETY_ERROR("safety check failed: " # exp " is true");  \
163             return val;                                                   \
164          }                                                                \
165     }                                                                     \
166   while (0)
167 
168 #define EINA_SAFETY_ON_TRUE_GOTO(exp, label)                              \
169   do                                                                      \
170     {                                                                     \
171        if (EINA_UNLIKELY(exp))                                            \
172          {                                                                \
173             EINA_SAFETY_ERROR("safety check failed: " # exp " is true");  \
174             goto label;                                                   \
175          }                                                                \
176     }                                                                     \
177   while (0)
178 
179 #define EINA_SAFETY_ON_FALSE_RETURN(exp)                                   \
180   do                                                                       \
181     {                                                                      \
182        if (EINA_UNLIKELY(!(exp)))                                          \
183          {                                                                 \
184             EINA_SAFETY_ERROR("safety check failed: " # exp " is false");  \
185             return;                                                        \
186          }                                                                 \
187     }                                                                      \
188   while (0)
189 
190 #define EINA_SAFETY_ON_FALSE_RETURN_VAL(exp, val)                          \
191   do                                                                       \
192     {                                                                      \
193        if (EINA_UNLIKELY(!(exp)))                                          \
194          {                                                                 \
195             EINA_SAFETY_ERROR("safety check failed: " # exp " is false");  \
196             return val;                                                    \
197          }                                                                 \
198     }                                                                      \
199   while (0)
200 
201 #define EINA_SAFETY_ON_FALSE_GOTO(exp, label)                              \
202   do                                                                       \
203     {                                                                      \
204        if (EINA_UNLIKELY(!(exp)))                                          \
205          {                                                                 \
206             EINA_SAFETY_ERROR("safety check failed: " # exp " is false");  \
207             goto label;                                                    \
208          }                                                                 \
209     }                                                                      \
210   while (0)
211 
212 #ifdef EINA_ARG_NONNULL
213 /* make EINA_ARG_NONNULL void so GCC does not optimize safety checks */
214 #undef EINA_ARG_NONNULL
215 #define EINA_ARG_NONNULL(...)
216 #endif
217 
218 #else /* no safety checks */
219 
220 /**
221  * @def EINA_SAFETY_ON_NULL_RETURN
222  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
223  * @param[in] exp The expression to be evaluated.
224  */
225 #define EINA_SAFETY_ON_NULL_RETURN(exp) \
226   do { (void)(!(exp)); } while (0)
227 
228 /**
229  * @def EINA_SAFETY_ON_NULL_RETURN_VAL
230  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
231  * @param[in] exp The expression to be evaluated.
232  * @param[in] val The value to be returned.
233  */
234 #define EINA_SAFETY_ON_NULL_RETURN_VAL(exp, val) \
235   do { if (0 && !(exp)) { (void)val; } } while (0)
236 
237 /**
238  * @def EINA_SAFETY_ON_NULL_GOTO
239  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
240  * @param[in] exp The expression to be evaluated.
241  * @param[in] label The label to jump to.
242  */
243 #define EINA_SAFETY_ON_NULL_GOTO(exp, label) \
244   do { if (0 && (exp) == NULL) { goto label; } } while (0)
245 
246 /**
247  * @def EINA_SAFETY_ON_TRUE_RETURN
248  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
249  * @param[in] exp The expression to be evaluated.
250  */
251 #define EINA_SAFETY_ON_TRUE_RETURN(exp) \
252   do { (void)(exp); } while (0)
253 
254 /**
255  * @def EINA_SAFETY_ON_TRUE_RETURN_VAL
256  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
257  * @param[in] exp The expression to be evaluated.
258  * @param[in] val The value to be returned.
259  */
260 #define EINA_SAFETY_ON_TRUE_RETURN_VAL(exp, val) \
261   do { if (0 && (exp)) { (void)val; } } while (0)
262 
263 /**
264  * @def EINA_SAFETY_ON_TRUE_GOTO
265  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
266  * @param[in] exp The expression to be evaluated.
267  * @param[in] label The label to jump to.
268  */
269 #define EINA_SAFETY_ON_TRUE_GOTO(exp, label) \
270   do { if (0 && (exp)) { goto label; } } while (0)
271 
272 /**
273  * @def EINA_SAFETY_ON_FALSE_RETURN
274  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
275  * @param[in] exp The expression to be evaluated.
276  */
277 #define EINA_SAFETY_ON_FALSE_RETURN(exp) \
278   do { (void)(!(exp)); } while (0)
279 
280 /**
281  * @def EINA_SAFETY_ON_FALSE_RETURN_VAL
282  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
283  * @param[in] exp The expression to be evaluated.
284  * @param[in] val The value to be returned.
285  */
286 #define EINA_SAFETY_ON_FALSE_RETURN_VAL(exp, val) \
287   do { if (0 && !(exp)) { (void)val; } } while (0)
288 
289 /**
290  * @def EINA_SAFETY_ON_FALSE_GOTO
291  * @brief The macro doesn't do anything unless EINA_SAFETY_CHECKS is defined.
292  * @param[in] exp The expression to be evaluated.
293  * @param[in] label The label to jump to.
294  */
295 #define EINA_SAFETY_ON_FALSE_GOTO(exp, label) \
296   do { if (0 && !(exp)) { goto label; } } while (0)
297 
298 #endif /* safety checks macros */
299 #endif /* EINA_SAFETY_CHECKS_H_ */
300 
301 /**
302  * @}
303  */
304 
305 /**
306  * @}
307  */
308