Line data Source code
1 : /**********************************************************************
2 : *
3 : * Name: cpl_error.h
4 : * Project: CPL - Common Portability Library
5 : * Purpose: CPL Error handling
6 : * Author: Daniel Morissette, danmo@videotron.ca
7 : *
8 : **********************************************************************
9 : * Copyright (c) 1998, Daniel Morissette
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #ifndef CPL_ERROR_H_INCLUDED
15 : #define CPL_ERROR_H_INCLUDED
16 :
17 : #include "cpl_port.h"
18 :
19 : #include <stdarg.h>
20 : #include <stdbool.h>
21 : #include <stddef.h>
22 :
23 : /*=====================================================================
24 : Error handling functions (cpl_error.c)
25 : =====================================================================*/
26 :
27 : /**
28 : * \file cpl_error.h
29 : *
30 : * CPL error handling services.
31 : */
32 :
33 : CPL_C_START
34 :
35 : /** Error category */
36 : typedef enum
37 : {
38 : CE_None = 0,
39 : CE_Debug = 1,
40 : CE_Warning = 2,
41 : CE_Failure = 3,
42 : CE_Fatal = 4
43 : } CPLErr;
44 :
45 : /* ==================================================================== */
46 : /* Well known error codes. */
47 : /* ==================================================================== */
48 :
49 : #ifdef STRICT_CPLERRORNUM_TYPE
50 :
51 : /* This is not appropriate for the general case, as there are parts */
52 : /* of GDAL which use custom error codes, but this can help diagnose confusions
53 : */
54 : /* between CPLErr and CPLErrorNum */
55 : typedef enum
56 : {
57 : CPLE_None,
58 : CPLE_AppDefined,
59 : CPLE_OutOfMemory,
60 : CPLE_FileIO,
61 : CPLE_OpenFailed,
62 : CPLE_IllegalArg,
63 : CPLE_NotSupported,
64 : CPLE_AssertionFailed,
65 : CPLE_NoWriteAccess,
66 : CPLE_UserInterrupt,
67 : CPLE_ObjectNull,
68 : CPLE_HttpResponse,
69 : CPLE_BucketNotFound,
70 : CPLE_ObjectNotFound,
71 : CPLE_AccessDenied,
72 : CPLE_InvalidCredentials,
73 : CPLE_SignatureDoesNotMatch,
74 : CPLE_ObjectStorageGenericError,
75 : } CPLErrorNum;
76 :
77 : #else
78 :
79 : /** Error number */
80 : typedef int CPLErrorNum;
81 :
82 : /** No error */
83 : #define CPLE_None 0
84 : /** Application defined error */
85 : #define CPLE_AppDefined 1
86 : /** Out of memory error */
87 : #define CPLE_OutOfMemory 2
88 : /** File I/O error */
89 : #define CPLE_FileIO 3
90 : /** Open failed */
91 : #define CPLE_OpenFailed 4
92 : /** Illegal argument */
93 : #define CPLE_IllegalArg 5
94 : /** Not supported */
95 : #define CPLE_NotSupported 6
96 : /** Assertion failed */
97 : #define CPLE_AssertionFailed 7
98 : /** No write access */
99 : #define CPLE_NoWriteAccess 8
100 : /** User interrupted */
101 : #define CPLE_UserInterrupt 9
102 : /** NULL object */
103 : #define CPLE_ObjectNull 10
104 :
105 : /*
106 : * Filesystem-specific errors
107 : */
108 : /** HTTP response */
109 : #define CPLE_HttpResponse 11
110 : /** VSIE_BucketNotFound */
111 : #define CPLE_BucketNotFound 12
112 : /** VSIE_ObjectNotFound */
113 : #define CPLE_ObjectNotFound 13
114 : /** VSIE_AccessDenied */
115 : #define CPLE_AccessDenied 14
116 : /** VSIE_InvalidCredentials */
117 : #define CPLE_InvalidCredentials 15
118 : /** VSIE_SignatureDoesNotMatch */
119 : #define CPLE_SignatureDoesNotMatch 16
120 : /** VSIE_ObjectStorageGenericError */
121 : #define CPLE_ObjectStorageGenericError 17
122 :
123 : /* 100 - 299 reserved for GDAL */
124 :
125 : #endif
126 :
127 : /** Deprecated alias for CPLE_BucketNotFound
128 : *
129 : * @deprecated since 3.12
130 : */
131 : #define CPLE_AWSBucketNotFound CPLE_BucketNotFound
132 :
133 : /** Deprecated alias for CPLE_ObjectNotFound
134 : *
135 : * @deprecated since 3.12
136 : */
137 : #define CPLE_AWSObjectNotFound CPLE_ObjectNotFound
138 :
139 : /** Deprecated alias for CPLE_AccessDenied
140 : *
141 : * @deprecated since 3.12
142 : */
143 : #define CPLE_AWSAccessDenied CPLE_AccessDenied
144 :
145 : /** Deprecated alias for CPLE_AWSInvalidCredentials
146 : *
147 : * @deprecated since 3.12
148 : */
149 : #define CPLE_AWSInvalidCredentials CPLE_InvalidCredentials
150 :
151 : /** Deprecated alias for CPLE_SignatureDoesNotMatch
152 : *
153 : * @deprecated since 3.12
154 : */
155 : #define CPLE_AWSSignatureDoesNotMatch CPLE_SignatureDoesNotMatch
156 :
157 : /** Deprecated alias for CPLE_ObjectStorageGenericError
158 : *
159 : * @deprecated since 3.12
160 : */
161 : #define CPLE_AWSError CPLE_ObjectStorageGenericError
162 :
163 : void CPL_DLL CPLError(CPLErr eErrClass, CPLErrorNum err_no,
164 : CPL_FORMAT_STRING(const char *fmt), ...)
165 : CPL_PRINT_FUNC_FORMAT(3, 4);
166 :
167 : #ifdef GDAL_COMPILATION
168 :
169 : const char CPL_DLL *CPLSPrintf(CPL_FORMAT_STRING(const char *fmt), ...)
170 : CPL_PRINT_FUNC_FORMAT(1, 2) CPL_WARN_UNUSED_RESULT;
171 :
172 : /** Similar to CPLError(), but only execute it once during the life-time
173 : * of a process.
174 : *
175 : * @since 3.11
176 : */
177 : #define CPLErrorOnce(eErrClass, err_no, ...) \
178 : do \
179 : { \
180 : static bool lbCPLErrorOnce = false; \
181 : if (!lbCPLErrorOnce) \
182 : { \
183 : lbCPLErrorOnce = true; \
184 : const char *lCPLErrorMsg = CPLSPrintf(__VA_ARGS__); \
185 : const size_t lCPLErrorMsgLen = strlen(lCPLErrorMsg); \
186 : const char *lCPLErrorMsgSuffix = \
187 : " Further messages of this type will be suppressed."; \
188 : if (lCPLErrorMsgLen && lCPLErrorMsg[lCPLErrorMsgLen - 1] == '.') \
189 : CPLError((eErrClass), (err_no), "%s%s", lCPLErrorMsg, \
190 : lCPLErrorMsgSuffix); \
191 : else \
192 : CPLError((eErrClass), (err_no), "%s.%s", lCPLErrorMsg, \
193 : lCPLErrorMsgSuffix); \
194 : } \
195 : } while (0)
196 : #endif
197 :
198 : void CPL_DLL CPLErrorV(CPLErr, CPLErrorNum, const char *, va_list);
199 : void CPL_DLL CPLEmergencyError(const char *) CPL_NO_RETURN;
200 : void CPL_DLL CPL_STDCALL CPLErrorReset(void);
201 : CPLErrorNum CPL_DLL CPL_STDCALL CPLGetLastErrorNo(void);
202 : CPLErr CPL_DLL CPL_STDCALL CPLGetLastErrorType(void);
203 : const char CPL_DLL *CPL_STDCALL CPLGetLastErrorMsg(void);
204 : GUInt32 CPL_DLL CPL_STDCALL CPLGetErrorCounter(void);
205 : void CPL_DLL *CPL_STDCALL CPLGetErrorHandlerUserData(void);
206 : void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
207 : const char *pszMsg);
208 : #if defined(GDAL_COMPILATION) && defined(__cplusplus)
209 : extern "C++"
210 : {
211 : void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
212 : const char *pszMsg,
213 : const GUInt32 *pnErrorCounter);
214 : }
215 : #endif
216 :
217 : void CPL_DLL CPLCallPreviousHandler(CPLErr eErrClass, CPLErrorNum err_no,
218 : const char *pszMsg);
219 : /*! @cond Doxygen_Suppress */
220 : void CPL_DLL CPLCleanupErrorMutex(void);
221 : /*! @endcond */
222 :
223 : /** Callback for a custom error handler */
224 : typedef void(CPL_STDCALL *CPLErrorHandler)(CPLErr, CPLErrorNum, const char *);
225 :
226 : void CPL_DLL CPL_STDCALL CPLLoggingErrorHandler(CPLErr, CPLErrorNum,
227 : const char *);
228 : void CPL_DLL CPL_STDCALL CPLDefaultErrorHandler(CPLErr, CPLErrorNum,
229 : const char *);
230 : void CPL_DLL CPL_STDCALL CPLQuietErrorHandler(CPLErr, CPLErrorNum,
231 : const char *);
232 : void CPL_DLL CPL_STDCALL CPLQuietWarningsErrorHandler(CPLErr, CPLErrorNum,
233 : const char *);
234 : void CPL_DLL CPLTurnFailureIntoWarning(int bOn);
235 :
236 : CPLErrorHandler CPL_DLL CPLGetErrorHandler(void **ppUserData);
237 :
238 : CPLErrorHandler CPL_DLL CPL_STDCALL CPLSetErrorHandler(CPLErrorHandler);
239 : CPLErrorHandler CPL_DLL CPL_STDCALL CPLSetErrorHandlerEx(CPLErrorHandler,
240 : void *);
241 : void CPL_DLL CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler);
242 : void CPL_DLL CPL_STDCALL CPLPushErrorHandlerEx(CPLErrorHandler, void *);
243 : void CPL_DLL CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug);
244 : void CPL_DLL CPL_STDCALL CPLPopErrorHandler(void);
245 :
246 : #ifdef WITHOUT_CPLDEBUG
247 : #define CPLDebug(...) \
248 : do \
249 : { \
250 : } while (0) /* Eat all CPLDebug calls. */
251 : #define CPLDebugProgress(...) \
252 : do \
253 : { \
254 : } while (0) /* Eat all CPLDebugProgress calls. */
255 :
256 : #ifdef GDAL_COMPILATION
257 : /** Similar to CPLDebug(), but only execute it once during the life-time
258 : * of a process.
259 : *
260 : * @since 3.11
261 : */
262 : #define CPLDebugOnce(...) \
263 : do \
264 : { \
265 : } while (0)
266 : #endif
267 :
268 : #else
269 : void CPL_DLL CPLDebug(const char *, CPL_FORMAT_STRING(const char *), ...)
270 : CPL_PRINT_FUNC_FORMAT(2, 3);
271 : void CPL_DLL CPLDebugProgress(const char *, CPL_FORMAT_STRING(const char *),
272 : ...) CPL_PRINT_FUNC_FORMAT(2, 3);
273 :
274 : #ifdef GDAL_COMPILATION
275 : /** Similar to CPLDebug(), but only execute it once during the life-time
276 : * of a process.
277 : *
278 : * @since 3.11
279 : */
280 : #define CPLDebugOnce(category, ...) \
281 : do \
282 : { \
283 : static bool lbCPLDebugOnce = false; \
284 : if (!lbCPLDebugOnce) \
285 : { \
286 : lbCPLDebugOnce = true; \
287 : const char *lCPLDebugMsg = CPLSPrintf(__VA_ARGS__); \
288 : const size_t lCPLErrorMsgLen = strlen(lCPLDebugMsg); \
289 : const char *lCPLDebugMsgSuffix = \
290 : " Further messages of this type will be suppressed."; \
291 : if (lCPLErrorMsgLen && lCPLDebugMsg[lCPLErrorMsgLen - 1] == '.') \
292 : CPLDebug((category), "%s%s", lCPLDebugMsg, \
293 : lCPLDebugMsgSuffix); \
294 : else \
295 : CPLDebug((category), "%s.%s", lCPLDebugMsg, \
296 : lCPLDebugMsgSuffix); \
297 : } \
298 : } while (0)
299 : #endif
300 :
301 : #endif
302 :
303 : #if defined(DEBUG) || defined(GDAL_DEBUG)
304 : /** Same as CPLDebug(), but expands to nothing for non-DEBUG builds.
305 : * @since GDAL 3.1
306 : */
307 : #define CPLDebugOnly(...) CPLDebug(__VA_ARGS__)
308 : #else
309 : /** Same as CPLDebug(), but expands to nothing for non-DEBUG builds.
310 : * @since GDAL 3.1
311 : */
312 : #define CPLDebugOnly(...) \
313 : do \
314 : { \
315 : } while (0)
316 : #endif
317 :
318 : void CPL_DLL CPL_STDCALL _CPLAssert(const char *, const char *,
319 : int) CPL_NO_RETURN;
320 :
321 : #if defined(DEBUG) && !defined(CPPCHECK)
322 : /** Assert on an expression. Only enabled in DEBUG mode */
323 : #define CPLAssert(expr) \
324 : ((expr) ? (void)(0) : _CPLAssert(#expr, __FILE__, __LINE__))
325 : /** Assert on an expression in DEBUG mode. Evaluate it also in non-DEBUG mode
326 : * (useful to 'consume' a error return variable) */
327 : #define CPLAssertAlwaysEval(expr) CPLAssert(expr)
328 : #else
329 : /** Assert on an expression. Only enabled in DEBUG mode */
330 : #define CPLAssert(expr) \
331 : do \
332 : { \
333 : } while (0)
334 : #ifdef __cplusplus
335 : /** Assert on an expression in DEBUG mode. Evaluate it also in non-DEBUG mode
336 : * (useful to 'consume' a error return variable) */
337 : #define CPLAssertAlwaysEval(expr) CPL_IGNORE_RET_VAL(expr)
338 : #else
339 : /** Assert on an expression in DEBUG mode. Evaluate it also in non-DEBUG mode
340 : * (useful to 'consume' a error return variable) */
341 : #define CPLAssertAlwaysEval(expr) (void)(expr)
342 : #endif
343 : #endif
344 :
345 : CPL_C_END
346 :
347 : /*! @cond Doxygen_Suppress */
348 : /*
349 : * Helper macros used for input parameters validation.
350 : */
351 : #ifdef DEBUG
352 : #define VALIDATE_POINTER_ERR CE_Fatal
353 : #else
354 : #define VALIDATE_POINTER_ERR CE_Failure
355 : #endif
356 :
357 : /*! @endcond */
358 :
359 : #if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS)
360 :
361 : extern "C++"
362 : {
363 : /*! @cond Doxygen_Suppress */
364 : template <class T> T *CPLAssertNotNull(T *x) CPL_RETURNS_NONNULL;
365 :
366 3 : template <class T> T *CPLAssertNotNull(T *x)
367 : {
368 3 : CPLAssert(x);
369 3 : return x;
370 : }
371 :
372 : #include <memory>
373 : #include <string>
374 :
375 : /*! @endcond */
376 :
377 : /** Class that installs a (thread-local) error handler on construction, and
378 : * restore the initial one on destruction.
379 : */
380 : class CPL_DLL CPLErrorHandlerPusher
381 : {
382 : public:
383 : /** Constructor that installs a thread-local temporary error handler
384 : * (typically CPLQuietErrorHandler)
385 : */
386 104575 : explicit CPLErrorHandlerPusher(CPLErrorHandler hHandler)
387 : {
388 104575 : CPLPushErrorHandler(hHandler);
389 104592 : }
390 :
391 : /** Constructor that installs a thread-local temporary error handler,
392 : * and its user data.
393 : */
394 : CPLErrorHandlerPusher(CPLErrorHandler hHandler, void *user_data)
395 : {
396 : CPLPushErrorHandlerEx(hHandler, user_data);
397 : }
398 :
399 : /** Destructor that restores the initial error handler. */
400 104589 : ~CPLErrorHandlerPusher()
401 : {
402 104589 : CPLPopErrorHandler();
403 104556 : }
404 : };
405 :
406 : /** Class that saves the error state on construction, and
407 : * restores it on destruction.
408 : */
409 : class CPL_DLL CPLErrorStateBackuper
410 : {
411 : CPLErrorNum m_nLastErrorNum;
412 : CPLErr m_nLastErrorType;
413 : std::string m_osLastErrorMsg;
414 : GUInt32 m_nLastErrorCounter;
415 : std::unique_ptr<CPLErrorHandlerPusher> m_poErrorHandlerPusher;
416 :
417 : public:
418 : /** Constructor that backs up the error state, and optionally installs
419 : * a thread-local temporary error handler (typically CPLQuietErrorHandler).
420 : */
421 : explicit CPLErrorStateBackuper(CPLErrorHandler hHandler = nullptr);
422 :
423 : /** Destructor that restores the error state to its initial state
424 : * before construction.
425 : */
426 : ~CPLErrorStateBackuper();
427 : };
428 :
429 : /** Class that turns errors into warning on construction, and
430 : * restores the previous state on destruction.
431 : */
432 : class CPL_DLL CPLTurnFailureIntoWarningBackuper
433 : {
434 : public:
435 5215 : CPLTurnFailureIntoWarningBackuper()
436 : {
437 5215 : CPLTurnFailureIntoWarning(true);
438 5215 : }
439 :
440 5215 : ~CPLTurnFailureIntoWarningBackuper()
441 : {
442 5215 : CPLTurnFailureIntoWarning(false);
443 5215 : }
444 : };
445 : }
446 :
447 : #ifdef GDAL_COMPILATION
448 : /*! @cond Doxygen_Suppress */
449 : // internal only
450 : bool CPLIsDefaultErrorHandlerAndCatchDebug();
451 : /*! @endcond */
452 : #endif
453 :
454 : #endif
455 :
456 : /** Validate that a pointer is not NULL */
457 : #define VALIDATE_POINTER0(ptr, func) \
458 : do \
459 : { \
460 : if (CPL_NULLPTR == ptr) \
461 : { \
462 : CPLErr const ret = VALIDATE_POINTER_ERR; \
463 : CPLError(ret, CPLE_ObjectNull, \
464 : "Pointer \'%s\' is NULL in \'%s\'.\n", #ptr, (func)); \
465 : return; \
466 : } \
467 : } while (0)
468 :
469 : /** Validate that a pointer is not NULL, and return rc if it is NULL */
470 : #define VALIDATE_POINTER1(ptr, func, rc) \
471 : do \
472 : { \
473 : if (CPL_NULLPTR == ptr) \
474 : { \
475 : CPLErr const ret = VALIDATE_POINTER_ERR; \
476 : CPLError(ret, CPLE_ObjectNull, \
477 : "Pointer \'%s\' is NULL in \'%s\'.\n", #ptr, (func)); \
478 : return (rc); \
479 : } \
480 : } while (0)
481 :
482 : #endif /* CPL_ERROR_H_INCLUDED */
|