Line data Source code
1 :
2 : /**********************************************************************
3 : *
4 : * Name: cpl_error.cpp
5 : * Project: CPL - Common Portability Library
6 : * Purpose: Error handling functions.
7 : * Author: Daniel Morissette, danmo@videotron.ca
8 : *
9 : **********************************************************************
10 : * Copyright (c) 1998, Daniel Morissette
11 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 :
16 : #include "cpl_error.h"
17 :
18 : #include <cstdarg>
19 : #include <cstdio>
20 : #include <cstdlib>
21 : #include <cstring>
22 :
23 : #include <algorithm>
24 :
25 : #include "cpl_config.h"
26 : #include "cpl_conv.h"
27 : #include "cpl_multiproc.h"
28 : #include "cpl_string.h"
29 : #include "cpl_vsi.h"
30 : #include "cpl_error_internal.h"
31 :
32 : #if !defined(va_copy) && defined(__va_copy)
33 : #define va_copy __va_copy
34 : #endif
35 :
36 : #define TIMESTAMP_DEBUG
37 : // #define MEMORY_DEBUG
38 :
39 : static CPLMutex *hErrorMutex = nullptr;
40 : static void *pErrorHandlerUserData = nullptr;
41 : static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
42 : static bool gbCatchDebug = true;
43 :
44 : constexpr int DEFAULT_LAST_ERR_MSG_SIZE =
45 : #if !defined(HAVE_VSNPRINTF)
46 : 20000
47 : #else
48 : 500
49 : #endif
50 : ;
51 :
52 : typedef struct errHandler
53 : {
54 : struct errHandler *psNext;
55 : void *pUserData;
56 : CPLErrorHandler pfnHandler;
57 : bool bCatchDebug;
58 : } CPLErrorHandlerNode;
59 :
60 : typedef struct
61 : {
62 : CPLErrorNum nLastErrNo;
63 : CPLErr eLastErrType;
64 : CPLErrorHandlerNode *psHandlerStack;
65 : int nLastErrMsgMax;
66 : int nFailureIntoWarning;
67 : bool bProgressMode;
68 : bool bEmitNewlineBeforeNextDbgMsg;
69 : GUInt32 nErrorCounter;
70 : char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
71 : // Do not add anything here. szLastErrMsg must be the last field.
72 : // See CPLRealloc() below.
73 : } CPLErrorContext;
74 :
75 : constexpr CPLErrorContext sNoErrorContext = {0, CE_None, nullptr, 0, 0,
76 : false, false, 0, ""};
77 :
78 : constexpr CPLErrorContext sWarningContext = {
79 : 0, CE_Warning, nullptr, 0, 0, false, false, 0, "A warning was emitted"};
80 :
81 : constexpr CPLErrorContext sFailureContext = {
82 : 0, CE_Warning, nullptr, 0, 0, false, false, 0, "A failure was emitted"};
83 :
84 : #define IS_PREFEFINED_ERROR_CTX(psCtxt) \
85 : (psCtx == &sNoErrorContext || psCtx == &sWarningContext || \
86 : psCtxt == &sFailureContext)
87 :
88 : /************************************************************************/
89 : /* CPLErrorContextGetString() */
90 : /************************************************************************/
91 :
92 : // Makes clang -fsanitize=undefined happy since it doesn't like
93 : // dereferencing szLastErrMsg[i>=DEFAULT_LAST_ERR_MSG_SIZE]
94 :
95 718675 : static char *CPLErrorContextGetString(CPLErrorContext *psCtxt)
96 : {
97 718675 : return psCtxt->szLastErrMsg;
98 : }
99 :
100 : /************************************************************************/
101 : /* CPLGetErrorContext() */
102 : /************************************************************************/
103 :
104 66537900 : static CPLErrorContext *CPLGetErrorContext()
105 :
106 : {
107 66537900 : int bError = FALSE;
108 : CPLErrorContext *psCtx = reinterpret_cast<CPLErrorContext *>(
109 66537900 : CPLGetTLSEx(CTLS_ERRORCONTEXT, &bError));
110 66537600 : if (bError)
111 0 : return nullptr;
112 :
113 66537600 : if (psCtx == nullptr)
114 : {
115 : psCtx = static_cast<CPLErrorContext *>(
116 3358 : VSICalloc(sizeof(CPLErrorContext), 1));
117 3359 : if (psCtx == nullptr)
118 : {
119 0 : fprintf(stderr, "Out of memory attempting to report error.\n");
120 0 : return nullptr;
121 : }
122 3359 : psCtx->eLastErrType = CE_None;
123 3359 : psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
124 3359 : CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
125 : }
126 :
127 66537600 : return psCtx;
128 : }
129 :
130 : /************************************************************************/
131 : /* CPLGetErrorHandlerUserData() */
132 : /************************************************************************/
133 :
134 : /**
135 : * Fetch the user data for the error context
136 : *
137 : * Fetches the user data for the current error context. You can
138 : * set the user data for the error context when you add your handler by
139 : * issuing CPLSetErrorHandlerEx() and CPLPushErrorHandlerEx(). Note that
140 : * user data is primarily intended for providing context within error handlers
141 : * themselves, but they could potentially be abused in other useful ways with
142 : * the usual caveat emptor understanding.
143 : *
144 : * @return the user data pointer for the error context
145 : */
146 :
147 8136270 : void *CPL_STDCALL CPLGetErrorHandlerUserData(void)
148 : {
149 : // get the current threadlocal or global error context user data
150 8136270 : CPLErrorContext *psCtx = CPLGetErrorContext();
151 8136270 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
152 0 : abort();
153 8136270 : return reinterpret_cast<void *>(psCtx->psHandlerStack
154 8136270 : ? psCtx->psHandlerStack->pUserData
155 8136270 : : pErrorHandlerUserData);
156 : }
157 :
158 : /************************************************************************/
159 : /* CPLGetErrorHandler() */
160 : /************************************************************************/
161 :
162 : /**
163 : * Fetch the current error handler for the current error context.
164 : *
165 : * This will be the last error handler pushed in the thread-local error stack
166 : * with CPLPushErrorHandler()/CPLPushErrorHandlerEx(), or if the stack is
167 : * empty, the global error handler set with
168 : * CPLSetErrorHandler()/CPLSetErrorHandlerEx(), or the default global error
169 : * handler.
170 : *
171 : * @param[out] ppUserData Pointer to store the user data pointer. May be NULL
172 : * @since GDAL 3.7
173 : */
174 :
175 0 : CPLErrorHandler CPLGetErrorHandler(void **ppUserData)
176 : {
177 0 : CPLErrorContext *psCtx = CPLGetErrorContext();
178 :
179 0 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
180 : {
181 0 : fprintf(stderr, "CPLGetErrorHandler() failed.\n");
182 0 : if (ppUserData)
183 0 : *ppUserData = nullptr;
184 0 : return CPLDefaultErrorHandler;
185 : }
186 :
187 0 : if (psCtx->psHandlerStack != nullptr)
188 : {
189 0 : if (ppUserData)
190 0 : *ppUserData = psCtx->psHandlerStack->pUserData;
191 0 : return psCtx->psHandlerStack->pfnHandler;
192 : }
193 :
194 0 : CPLMutexHolderD(&hErrorMutex);
195 0 : if (ppUserData)
196 0 : *ppUserData = pErrorHandlerUserData;
197 0 : return pfnErrorHandler;
198 : }
199 :
200 : /************************************************************************/
201 : /* ApplyErrorHandler() */
202 : /************************************************************************/
203 :
204 111606 : static void ApplyErrorHandler(CPLErrorContext *psCtx, CPLErr eErrClass,
205 : CPLErrorNum err_no, const char *pszMessage)
206 : {
207 111606 : bool bProcessed = false;
208 :
209 111606 : if (psCtx->psHandlerStack != nullptr)
210 : {
211 : // iterate through the threadlocal handler stack
212 71028 : if ((eErrClass != CE_Debug) || psCtx->psHandlerStack->bCatchDebug)
213 : {
214 : // call the error handler
215 70950 : CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
216 70950 : psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMessage);
217 70950 : if (psNewCurNode != psCtx->psHandlerStack)
218 : {
219 0 : fprintf(stderr, "ApplyErrorHandler() has detected that a "
220 : "previous error handler messed up with the "
221 : "error stack. Chaos guaranteed!\n");
222 : }
223 70950 : bProcessed = true;
224 : }
225 : else
226 : {
227 : // need to iterate to a parent handler for debug messages
228 78 : CPLErrorHandlerNode *psNode = psCtx->psHandlerStack->psNext;
229 78 : while (psNode != nullptr)
230 : {
231 76 : if (psNode->bCatchDebug)
232 : {
233 76 : CPLErrorHandlerNode *psBackupCurNode =
234 : psCtx->psHandlerStack;
235 76 : psCtx->psHandlerStack = psNode;
236 76 : CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
237 76 : psNode->pfnHandler(eErrClass, err_no, pszMessage);
238 : // cppcheck-suppress knownConditionTrueFalse
239 76 : if (psNewCurNode != psCtx->psHandlerStack)
240 : {
241 0 : fprintf(stderr,
242 : "ApplyErrorHandler() has detected that a "
243 : "previous error handler messed up with the "
244 : "error stack. Chaos guaranteed!\n");
245 : }
246 76 : psCtx->psHandlerStack = psBackupCurNode;
247 76 : bProcessed = true;
248 76 : break;
249 : }
250 0 : psNode = psNode->psNext;
251 : }
252 : }
253 : }
254 :
255 111606 : if (!bProcessed)
256 : {
257 : // hit the global error handler
258 81160 : CPLMutexHolderD(&hErrorMutex);
259 40580 : if ((eErrClass != CE_Debug) || gbCatchDebug)
260 : {
261 40579 : if (pfnErrorHandler != nullptr)
262 : {
263 : // Make sure to empty the thread-specific handler stack,
264 : // otherwise the global error handler might get unrelated
265 : // data when calling CPLGetErrorHandlerUserData()
266 40577 : CPLErrorHandlerNode *psCurNodeBackup = psCtx->psHandlerStack;
267 40577 : psCtx->psHandlerStack = nullptr;
268 40577 : pfnErrorHandler(eErrClass, err_no, pszMessage);
269 40577 : psCtx->psHandlerStack = psCurNodeBackup;
270 40579 : }
271 : }
272 : else /* if( eErrClass == CE_Debug ) */
273 : {
274 : // for CPLDebug messages we propagate to the default error handler
275 1 : CPLDefaultErrorHandler(eErrClass, err_no, pszMessage);
276 : }
277 : }
278 111606 : }
279 :
280 : /**********************************************************************
281 : * CPLError()
282 : **********************************************************************/
283 :
284 : /**
285 : * Report an error.
286 : *
287 : * This function reports an error in a manner that can be hooked
288 : * and reported appropriate by different applications.
289 : *
290 : * The effect of this function can be altered by applications by installing
291 : * a custom error handling using CPLSetErrorHandler().
292 : *
293 : * The eErrClass argument can have the value CE_Warning indicating that the
294 : * message is an informational warning, CE_Failure indicating that the
295 : * action failed, but that normal recover mechanisms will be used or
296 : * CE_Fatal meaning that a fatal error has occurred, and that CPLError()
297 : * should not return.
298 : *
299 : * The default behavior of CPLError() is to report errors to stderr,
300 : * and to abort() after reporting a CE_Fatal error. It is expected that
301 : * some applications will want to suppress error reporting, and will want to
302 : * install a C++ exception, or longjmp() approach to no local fatal error
303 : * recovery.
304 : *
305 : * Regardless of how application error handlers or the default error
306 : * handler choose to handle an error, the error number, and message will
307 : * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
308 : *
309 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
310 : * @param err_no the error number (CPLE_*) from cpl_error.h.
311 : * @param fmt a printf() style format string. Any additional arguments
312 : * will be treated as arguments to fill in this format in a manner
313 : * similar to printf().
314 : */
315 :
316 102697 : void CPLError(CPLErr eErrClass, CPLErrorNum err_no,
317 : CPL_FORMAT_STRING(const char *fmt), ...)
318 : {
319 : va_list args;
320 :
321 : // Expand the error message.
322 102697 : va_start(args, fmt);
323 102697 : CPLErrorV(eErrClass, err_no, fmt, args);
324 102697 : va_end(args);
325 102697 : }
326 :
327 : /************************************************************************/
328 : /* CPLErrorV() */
329 : /************************************************************************/
330 :
331 : /** Same as CPLError() but with a va_list */
332 109672 : void CPLErrorV(CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
333 : va_list args)
334 : {
335 109672 : CPLErrorContext *psCtx = CPLGetErrorContext();
336 109669 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
337 : {
338 1 : int bMemoryError = FALSE;
339 1 : if (eErrClass == CE_Warning)
340 : {
341 0 : CPLSetTLSWithFreeFuncEx(
342 : CTLS_ERRORCONTEXT,
343 : reinterpret_cast<void *>(
344 : const_cast<CPLErrorContext *>(&sWarningContext)),
345 : nullptr, &bMemoryError);
346 : }
347 1 : else if (eErrClass == CE_Failure)
348 : {
349 0 : CPLSetTLSWithFreeFuncEx(
350 : CTLS_ERRORCONTEXT,
351 : reinterpret_cast<void *>(
352 : const_cast<CPLErrorContext *>(&sFailureContext)),
353 : nullptr, &bMemoryError);
354 : }
355 :
356 : // TODO: Is it possible to move the entire szShortMessage under the if
357 : // pfnErrorHandler?
358 1 : char szShortMessage[80] = {};
359 1 : CPLvsnprintf(szShortMessage, sizeof(szShortMessage), fmt, args);
360 :
361 0 : CPLMutexHolderD(&hErrorMutex);
362 0 : if (pfnErrorHandler != nullptr)
363 0 : pfnErrorHandler(eErrClass, err_no, szShortMessage);
364 0 : return;
365 : }
366 :
367 109668 : if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
368 6 : eErrClass = CE_Warning;
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Expand the error message */
372 : /* -------------------------------------------------------------------- */
373 : #if defined(HAVE_VSNPRINTF)
374 : {
375 : va_list wrk_args;
376 :
377 : #ifdef va_copy
378 109668 : va_copy(wrk_args, args);
379 : #else
380 : wrk_args = args;
381 : #endif
382 :
383 : /* --------------------------------------------------------------------
384 : */
385 : /* If CPL_ACCUM_ERROR_MSG=ON accumulate the error messages, */
386 : /* rather than just replacing the last error message. */
387 : /* --------------------------------------------------------------------
388 : */
389 109668 : int nPreviousSize = 0;
390 179575 : if (psCtx->psHandlerStack != nullptr &&
391 69904 : EQUAL(CPLGetConfigOption("CPL_ACCUM_ERROR_MSG", ""), "ON"))
392 : {
393 0 : nPreviousSize = static_cast<int>(strlen(psCtx->szLastErrMsg));
394 0 : if (nPreviousSize)
395 : {
396 0 : if (nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax)
397 : {
398 0 : psCtx->nLastErrMsgMax *= 3;
399 : psCtx = static_cast<CPLErrorContext *>(
400 0 : CPLRealloc(psCtx, sizeof(CPLErrorContext) -
401 : DEFAULT_LAST_ERR_MSG_SIZE +
402 0 : psCtx->nLastErrMsgMax + 1));
403 0 : CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
404 : }
405 0 : char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
406 0 : pszLastErrMsg[nPreviousSize] = '\n';
407 0 : pszLastErrMsg[nPreviousSize + 1] = '\0';
408 0 : nPreviousSize++;
409 : }
410 : }
411 :
412 109671 : int nPR = 0;
413 20 : while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
414 109691 : psCtx->nLastErrMsgMax - nPreviousSize, fmt,
415 109683 : wrk_args)) == -1 ||
416 109711 : nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
417 24 : psCtx->nLastErrMsgMax < 1000000)
418 : {
419 : #ifdef va_copy
420 20 : va_end(wrk_args);
421 20 : va_copy(wrk_args, args);
422 : #else
423 : wrk_args = args;
424 : #endif
425 20 : psCtx->nLastErrMsgMax *= 3;
426 40 : psCtx = static_cast<CPLErrorContext *>(CPLRealloc(
427 : psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
428 20 : psCtx->nLastErrMsgMax + 1));
429 20 : CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
430 : }
431 :
432 109667 : va_end(wrk_args);
433 : }
434 : #else
435 : // !HAVE_VSNPRINTF
436 : CPLvsnprintf(psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
437 : #endif
438 :
439 : /* -------------------------------------------------------------------- */
440 : /* Obfuscate any password in error message */
441 : /* -------------------------------------------------------------------- */
442 109667 : char *pszPassword = strstr(psCtx->szLastErrMsg, "password=");
443 109667 : if (pszPassword != nullptr)
444 : {
445 0 : char *pszIter = pszPassword + strlen("password=");
446 0 : while (*pszIter != ' ' && *pszIter != '\0')
447 : {
448 0 : *pszIter = 'X';
449 0 : pszIter++;
450 : }
451 : }
452 :
453 : /* -------------------------------------------------------------------- */
454 : /* If the user provided an handling function, then */
455 : /* call it, otherwise print the error to stderr and return. */
456 : /* -------------------------------------------------------------------- */
457 109667 : psCtx->nLastErrNo = err_no;
458 109667 : psCtx->eLastErrType = eErrClass;
459 109667 : if (psCtx->nErrorCounter == ~(0U))
460 0 : psCtx->nErrorCounter = 0;
461 : else
462 109667 : psCtx->nErrorCounter++;
463 :
464 109667 : if (CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr)
465 0 : CPLDebug("CPLError", "%s", psCtx->szLastErrMsg);
466 :
467 : /* -------------------------------------------------------------------- */
468 : /* Invoke the current error handler. */
469 : /* -------------------------------------------------------------------- */
470 109672 : ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
471 :
472 109672 : if (eErrClass == CE_Fatal)
473 0 : abort();
474 : }
475 :
476 : /************************************************************************/
477 : /* CPLEmergencyError() */
478 : /************************************************************************/
479 :
480 : /**
481 : * Fatal error when things are bad.
482 : *
483 : * This function should be called in an emergency situation where
484 : * it is unlikely that a regular error report would work. This would
485 : * include in the case of heap exhaustion for even small allocations,
486 : * or any failure in the process of reporting an error (such as TLS
487 : * allocations).
488 : *
489 : * This function should never return. After the error message has been
490 : * reported as best possible, the application will abort() similarly to how
491 : * CPLError() aborts on CE_Fatal class errors.
492 : *
493 : * @param pszMessage the error message to report.
494 : */
495 :
496 0 : void CPLEmergencyError(const char *pszMessage)
497 : {
498 : static bool bInEmergencyError = false;
499 :
500 : // If we are already in emergency error then one of the
501 : // following failed, so avoid them the second time through.
502 0 : if (!bInEmergencyError)
503 : {
504 0 : bInEmergencyError = true;
505 : CPLErrorContext *psCtx =
506 0 : static_cast<CPLErrorContext *>(CPLGetTLS(CTLS_ERRORCONTEXT));
507 :
508 0 : ApplyErrorHandler(psCtx, CE_Fatal, CPLE_AppDefined, pszMessage);
509 : }
510 :
511 : // Ultimate fallback.
512 0 : fprintf(stderr, "FATAL: %s\n", pszMessage);
513 :
514 0 : abort();
515 : }
516 :
517 : /************************************************************************/
518 : /* CPLGetProcessMemorySize() */
519 : /************************************************************************/
520 :
521 : #ifdef MEMORY_DEBUG
522 :
523 : #ifdef __linux
524 : static int CPLGetProcessMemorySize()
525 : {
526 : FILE *fp = fopen("/proc/self/status", "r");
527 : if (fp == nullptr)
528 : return -1;
529 : int nRet = -1;
530 : char szLine[128] = {};
531 : while (fgets(szLine, sizeof(szLine), fp) != nullptr)
532 : {
533 : if (STARTS_WITH(szLine, "VmSize:"))
534 : {
535 : const char *pszPtr = szLine;
536 : while (!(*pszPtr == '\0' || (*pszPtr >= '0' && *pszPtr <= '9')))
537 : pszPtr++;
538 : nRet = atoi(pszPtr);
539 : break;
540 : }
541 : }
542 : fclose(fp);
543 : return nRet;
544 : }
545 : #else
546 : #error CPLGetProcessMemorySize() unimplemented for this OS
547 : #endif
548 :
549 : #endif // def MEMORY_DEBUG
550 :
551 : /************************************************************************/
552 : /* CPLGettimeofday() */
553 : /************************************************************************/
554 :
555 : #if defined(_WIN32) && !defined(__CYGWIN__)
556 : #include <sys/timeb.h>
557 :
558 : namespace
559 : {
560 : struct CPLTimeVal
561 : {
562 : time_t tv_sec; /* seconds */
563 : long tv_usec; /* and microseconds */
564 : };
565 : } // namespace
566 :
567 : static int CPLGettimeofday(struct CPLTimeVal *tp, void * /* timezonep*/)
568 : {
569 : struct _timeb theTime;
570 :
571 : _ftime(&theTime);
572 : tp->tv_sec = static_cast<time_t>(theTime.time);
573 : tp->tv_usec = theTime.millitm * 1000;
574 : return 0;
575 : }
576 : #else
577 : #include <sys/time.h> /* for gettimeofday() */
578 : #define CPLTimeVal timeval
579 : #define CPLGettimeofday(t, u) gettimeofday(t, u)
580 : #endif
581 :
582 : #ifndef WITHOUT_CPLDEBUG
583 :
584 : /************************************************************************/
585 : /* CPLvDebug() */
586 : /************************************************************************/
587 :
588 756654 : static void CPLvDebug(const char *pszCategory,
589 : CPL_FORMAT_STRING(const char *pszFormat), va_list args)
590 : {
591 756654 : CPLErrorContext *psCtx = CPLGetErrorContext();
592 756522 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
593 0 : return;
594 756621 : const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
595 :
596 : /* -------------------------------------------------------------------- */
597 : /* Does this message pass our current criteria? */
598 : /* -------------------------------------------------------------------- */
599 756765 : if (pszDebug == nullptr || EQUAL(pszDebug, "NO") ||
600 2045 : EQUAL(pszDebug, "OFF") || EQUAL(pszDebug, "FALSE") ||
601 2025 : EQUAL(pszDebug, "0"))
602 : {
603 754742 : return;
604 : }
605 :
606 2023 : if (!EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, "YES") &&
607 160 : !EQUAL(pszDebug, "TRUE") && !EQUAL(pszDebug, "1") &&
608 148 : !EQUAL(pszDebug, ""))
609 : {
610 : // check if value of CPL_DEBUG contains the category
611 147 : const size_t nLen = strlen(pszCategory);
612 :
613 147 : size_t i = 0;
614 1066 : for (i = 0; pszDebug[i] != '\0'; i++)
615 : {
616 977 : if (EQUALN(pszCategory, pszDebug + i, nLen))
617 58 : break;
618 : }
619 :
620 147 : if (pszDebug[i] == '\0')
621 89 : return;
622 : }
623 :
624 : /* -------------------------------------------------------------------- */
625 : /* Allocate a block for the error. */
626 : /* -------------------------------------------------------------------- */
627 1934 : const int ERROR_MAX = 25000;
628 1934 : char *pszMessage = static_cast<char *>(VSIMalloc(ERROR_MAX));
629 1934 : if (pszMessage == nullptr)
630 0 : return;
631 :
632 : /* -------------------------------------------------------------------- */
633 : /* Dal -- always log a timestamp as the first part of the line */
634 : /* to ensure one is looking at what one should be looking at! */
635 : /* -------------------------------------------------------------------- */
636 :
637 1934 : pszMessage[0] = '\0';
638 : #ifdef TIMESTAMP_DEBUG
639 1934 : if (CPLTestBool(CPLGetConfigOption("CPL_TIMESTAMP", "NO")))
640 : {
641 : static struct CPLTimeVal tvStart;
642 6 : static const auto unused = CPLGettimeofday(&tvStart, nullptr);
643 6 : CPL_IGNORE_RET_VAL(unused);
644 : struct CPLTimeVal tv;
645 6 : CPLGettimeofday(&tv, nullptr);
646 6 : strcpy(pszMessage, "[");
647 6 : strcat(pszMessage, VSICTime(static_cast<unsigned long>(tv.tv_sec)));
648 :
649 : // On windows anyway, ctime puts a \n at the end, but I'm not
650 : // convinced this is standard behavior, so we'll get rid of it
651 : // carefully
652 :
653 6 : if (pszMessage[strlen(pszMessage) - 1] == '\n')
654 : {
655 6 : pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
656 : }
657 6 : CPLsnprintf(pszMessage + strlen(pszMessage),
658 6 : ERROR_MAX - strlen(pszMessage),
659 6 : "].%04d, %03.04f: ", static_cast<int>(tv.tv_usec / 100),
660 6 : tv.tv_sec + tv.tv_usec * 1e-6 -
661 6 : (tvStart.tv_sec + tvStart.tv_usec * 1e-6));
662 : }
663 : #endif
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* Add the process memory size. */
667 : /* -------------------------------------------------------------------- */
668 : #ifdef MEMORY_DEBUG
669 : char szVmSize[32] = {};
670 : CPLsprintf(szVmSize, "[VmSize: %d] ", CPLGetProcessMemorySize());
671 : strcat(pszMessage, szVmSize);
672 : #endif
673 :
674 : /* -------------------------------------------------------------------- */
675 : /* Add the category. */
676 : /* -------------------------------------------------------------------- */
677 1934 : strcat(pszMessage, pszCategory);
678 1934 : strcat(pszMessage, ": ");
679 :
680 : /* -------------------------------------------------------------------- */
681 : /* Format the application provided portion of the debug message. */
682 : /* -------------------------------------------------------------------- */
683 1934 : CPLvsnprintf(pszMessage + strlen(pszMessage),
684 1934 : ERROR_MAX - strlen(pszMessage), pszFormat, args);
685 :
686 : /* -------------------------------------------------------------------- */
687 : /* Obfuscate any password in error message */
688 : /* -------------------------------------------------------------------- */
689 :
690 1934 : char *pszPassword = strstr(pszMessage, "password=");
691 1934 : if (pszPassword != nullptr)
692 : {
693 0 : char *pszIter = pszPassword + strlen("password=");
694 0 : while (*pszIter != ' ' && *pszIter != '\0')
695 : {
696 0 : *pszIter = 'X';
697 0 : pszIter++;
698 : }
699 : }
700 :
701 : /* -------------------------------------------------------------------- */
702 : /* Invoke the current error handler. */
703 : /* -------------------------------------------------------------------- */
704 1934 : ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
705 :
706 1934 : VSIFree(pszMessage);
707 : }
708 :
709 : #endif // !WITHOUT_CPLDEBUG
710 :
711 : /************************************************************************/
712 : /* CPLDebug() */
713 : /************************************************************************/
714 :
715 : /**
716 : * Display a debugging message.
717 : *
718 : * The category argument is used in conjunction with the CPL_DEBUG
719 : * environment variable to establish if the message should be displayed.
720 : * If the CPL_DEBUG environment variable is not set, no debug messages
721 : * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
722 : * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
723 : * debug messages are shown. Otherwise only messages whose category appears
724 : * somewhere within the CPL_DEBUG value are displayed (as determined by
725 : * strstr()).
726 : *
727 : * Categories are usually an identifier for the subsystem producing the
728 : * error. For instance "GDAL" might be used for the GDAL core, and "TIFF"
729 : * for messages from the TIFF translator.
730 : *
731 : * @param pszCategory name of the debugging message category.
732 : * @param pszFormat printf() style format string for message to display.
733 : * Remaining arguments are assumed to be for format.
734 : */
735 :
736 : #ifdef WITHOUT_CPLDEBUG
737 : // Do not include CPLDebug. Only available in custom builds.
738 : #else
739 :
740 756728 : void CPLDebug(const char *pszCategory, CPL_FORMAT_STRING(const char *pszFormat),
741 : ...)
742 :
743 : {
744 : va_list args;
745 756728 : va_start(args, pszFormat);
746 756728 : CPLvDebug(pszCategory, pszFormat, args);
747 756763 : va_end(args);
748 756763 : }
749 :
750 : #endif // WITHOUT_CPLDEBUG
751 :
752 : /************************************************************************/
753 : /* CPLDebugProgress() */
754 : /************************************************************************/
755 :
756 : /**
757 : * Display a debugging message indicating a progression.
758 : *
759 : * This is the same as CPLDebug(), except that when displaying on the terminal,
760 : * it will erase the previous debug progress message. This is for example
761 : * appropriate to display increasing percentages for a task.
762 : *
763 : * The category argument is used in conjunction with the CPL_DEBUG
764 : * environment variable to establish if the message should be displayed.
765 : * If the CPL_DEBUG environment variable is not set, no debug messages
766 : * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
767 : * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
768 : * debug messages are shown. Otherwise only messages whose category appears
769 : * somewhere within the CPL_DEBUG value are displayed (as determined by
770 : * strstr()).
771 : *
772 : * Categories are usually an identifier for the subsystem producing the
773 : * error. For instance "GDAL" might be used for the GDAL core, and "TIFF"
774 : * for messages from the TIFF translator.
775 : *
776 : * @param pszCategory name of the debugging message category.
777 : * @param pszFormat printf() style format string for message to display.
778 : * Remaining arguments are assumed to be for format.
779 : * @since 3.9
780 : */
781 :
782 : #ifdef WITHOUT_CPLDEBUG
783 : // Do not include CPLDebugProgress. Only available in custom builds.
784 : #else
785 2 : void CPLDebugProgress(const char *pszCategory,
786 : CPL_FORMAT_STRING(const char *pszFormat), ...)
787 :
788 : {
789 2 : CPLErrorContext *psCtx = CPLGetErrorContext();
790 2 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
791 0 : return;
792 :
793 2 : psCtx->bProgressMode = true;
794 :
795 : va_list args;
796 2 : va_start(args, pszFormat);
797 2 : CPLvDebug(pszCategory, pszFormat, args);
798 2 : va_end(args);
799 :
800 2 : psCtx->bProgressMode = false;
801 : }
802 : #endif // !WITHOUT_CPLDEBUG
803 :
804 : /**********************************************************************
805 : * CPLErrorReset()
806 : **********************************************************************/
807 :
808 : /**
809 : * Erase any traces of previous errors.
810 : *
811 : * This is normally used to ensure that an error which has been recovered
812 : * from does not appear to be still in play with high level functions.
813 : */
814 :
815 8991710 : void CPL_STDCALL CPLErrorReset()
816 : {
817 8991710 : CPLErrorContext *psCtx = CPLGetErrorContext();
818 8991710 : if (psCtx == nullptr)
819 0 : return;
820 8991710 : if (IS_PREFEFINED_ERROR_CTX(psCtx))
821 : {
822 2 : int bMemoryError = FALSE;
823 2 : CPLSetTLSWithFreeFuncEx(
824 : CTLS_ERRORCONTEXT,
825 : reinterpret_cast<void *>(
826 : const_cast<CPLErrorContext *>(&sNoErrorContext)),
827 : nullptr, &bMemoryError);
828 0 : return;
829 : }
830 :
831 8991710 : psCtx->nLastErrNo = CPLE_None;
832 8991710 : psCtx->szLastErrMsg[0] = '\0';
833 8991710 : psCtx->eLastErrType = CE_None;
834 8991710 : psCtx->nErrorCounter = 0;
835 : }
836 :
837 : /**********************************************************************
838 : * CPLErrorSetState()
839 : **********************************************************************/
840 :
841 718671 : void CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no, const char *pszMsg,
842 : const GUInt32 *pnErrorCounter)
843 : {
844 718671 : CPLErrorContext *psCtx = CPLGetErrorContext();
845 718668 : if (psCtx == nullptr)
846 0 : return;
847 718668 : if (IS_PREFEFINED_ERROR_CTX(psCtx))
848 : {
849 5 : int bMemoryError = FALSE;
850 5 : if (eErrClass == CE_None)
851 0 : CPLSetTLSWithFreeFuncEx(
852 : CTLS_ERRORCONTEXT,
853 : reinterpret_cast<void *>(
854 : const_cast<CPLErrorContext *>(&sNoErrorContext)),
855 : nullptr, &bMemoryError);
856 5 : else if (eErrClass == CE_Warning)
857 0 : CPLSetTLSWithFreeFuncEx(
858 : CTLS_ERRORCONTEXT,
859 : reinterpret_cast<void *>(
860 : const_cast<CPLErrorContext *>(&sWarningContext)),
861 : nullptr, &bMemoryError);
862 5 : else if (eErrClass == CE_Failure)
863 0 : CPLSetTLSWithFreeFuncEx(
864 : CTLS_ERRORCONTEXT,
865 : reinterpret_cast<void *>(
866 : const_cast<CPLErrorContext *>(&sFailureContext)),
867 : nullptr, &bMemoryError);
868 0 : return;
869 : }
870 :
871 718663 : psCtx->nLastErrNo = err_no;
872 1437330 : const size_t size = std::min(static_cast<size_t>(psCtx->nLastErrMsgMax - 1),
873 718663 : strlen(pszMsg));
874 718664 : char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
875 718669 : memcpy(pszLastErrMsg, pszMsg, size);
876 718669 : pszLastErrMsg[size] = '\0';
877 718669 : psCtx->eLastErrType = eErrClass;
878 718669 : if (pnErrorCounter)
879 158595 : psCtx->nErrorCounter = *pnErrorCounter;
880 : }
881 :
882 : /**
883 : * Restore an error state, without emitting an error.
884 : *
885 : * Can be useful if a routine might call CPLErrorReset() and one wants to
886 : * preserve the previous error state.
887 : *
888 : */
889 :
890 560075 : void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
891 : const char *pszMsg)
892 : {
893 560075 : CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
894 560074 : }
895 :
896 : /**********************************************************************
897 : * CPLGetLastErrorNo()
898 : **********************************************************************/
899 :
900 : /**
901 : * Fetch the last error number.
902 : *
903 : * Fetches the last error number posted with CPLError(), that hasn't
904 : * been cleared by CPLErrorReset(). This is the error number, not the error
905 : * class.
906 : *
907 : * @return the error number of the last error to occur, or CPLE_None (0)
908 : * if there are no posted errors.
909 : */
910 :
911 882062 : CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
912 : {
913 882062 : CPLErrorContext *psCtx = CPLGetErrorContext();
914 882008 : if (psCtx == nullptr)
915 0 : return 0;
916 :
917 882008 : return psCtx->nLastErrNo;
918 : }
919 :
920 : /**********************************************************************
921 : * CPLGetLastErrorType()
922 : **********************************************************************/
923 :
924 : /**
925 : * Fetch the last error type.
926 : *
927 : * Fetches the last error type posted with CPLError(), that hasn't
928 : * been cleared by CPLErrorReset(). This is the error class, not the error
929 : * number.
930 : *
931 : * @return the error type of the last error to occur, or CE_None (0)
932 : * if there are no posted errors.
933 : */
934 :
935 11712900 : CPLErr CPL_STDCALL CPLGetLastErrorType()
936 : {
937 11712900 : CPLErrorContext *psCtx = CPLGetErrorContext();
938 11712900 : if (psCtx == nullptr)
939 0 : return CE_None;
940 :
941 11712900 : return psCtx->eLastErrType;
942 : }
943 :
944 : /**********************************************************************
945 : * CPLGetLastErrorMsg()
946 : **********************************************************************/
947 :
948 : /**
949 : * Get the last error message.
950 : *
951 : * Fetches the last error message posted with CPLError(), that hasn't
952 : * been cleared by CPLErrorReset(). The returned pointer is to an internal
953 : * string that should not be altered or freed.
954 : *
955 : * @return the last error message, or an empty string ("") if there is no
956 : * posted error message.
957 : */
958 :
959 437117 : const char *CPL_STDCALL CPLGetLastErrorMsg()
960 : {
961 437117 : CPLErrorContext *psCtx = CPLGetErrorContext();
962 437113 : if (psCtx == nullptr)
963 0 : return "";
964 :
965 437113 : return psCtx->szLastErrMsg;
966 : }
967 :
968 : /**********************************************************************
969 : * CPLGetErrorCounter()
970 : **********************************************************************/
971 :
972 : /**
973 : * Get the error counter
974 : *
975 : * Fetches the number of errors emitted in the current error context,
976 : * since the last call to CPLErrorReset()
977 : *
978 : * @return the error counter.
979 : */
980 :
981 17807300 : GUInt32 CPL_STDCALL CPLGetErrorCounter()
982 : {
983 17807300 : CPLErrorContext *psCtx = CPLGetErrorContext();
984 17807700 : if (psCtx == nullptr)
985 0 : return 0;
986 :
987 17807700 : return psCtx->nErrorCounter;
988 : }
989 :
990 : /************************************************************************/
991 : /* CPLDefaultErrorHandler() */
992 : /************************************************************************/
993 :
994 : static FILE *fpLog = stderr;
995 : static bool bLogInit = false;
996 :
997 13 : static FILE *CPLfopenUTF8(const char *pszFilename, const char *pszAccess)
998 : {
999 : FILE *f;
1000 : #ifdef _WIN32
1001 : wchar_t *pwszFilename =
1002 : CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
1003 : wchar_t *pwszAccess =
1004 : CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
1005 : f = _wfopen(pwszFilename, pwszAccess);
1006 : VSIFree(pwszFilename);
1007 : VSIFree(pwszAccess);
1008 : #else
1009 13 : f = fopen(pszFilename, pszAccess);
1010 : #endif
1011 13 : return f;
1012 : }
1013 :
1014 : /** Default error handler. */
1015 60996 : void CPL_STDCALL CPLDefaultErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1016 : const char *pszErrorMsg)
1017 :
1018 : {
1019 : static int nCount = 0;
1020 : static int nMaxErrors = -1;
1021 : static char chErrorSeparator = ':';
1022 :
1023 60996 : if (eErrClass != CE_Debug)
1024 : {
1025 59876 : if (nMaxErrors == -1)
1026 : {
1027 251 : nMaxErrors =
1028 251 : atoi(CPLGetConfigOption("CPL_MAX_ERROR_REPORTS", "1000"));
1029 : // If running GDAL as a CustomBuild Command os MSBuild, "ERROR bla:"
1030 : // is considered as failing the job. This is rarely the intended
1031 : // behavior
1032 : const char *pszErrorSeparator =
1033 251 : CPLGetConfigOption("CPL_ERROR_SEPARATOR", ":");
1034 251 : if (pszErrorSeparator[0])
1035 251 : chErrorSeparator = pszErrorSeparator[0];
1036 : }
1037 :
1038 59876 : nCount++;
1039 59876 : if (nCount > nMaxErrors && nMaxErrors > 0)
1040 55813 : return;
1041 : }
1042 :
1043 5183 : if (!bLogInit)
1044 : {
1045 275 : bLogInit = true;
1046 :
1047 275 : fpLog = stderr;
1048 275 : const char *pszLog = CPLGetConfigOption("CPL_LOG", nullptr);
1049 275 : if (pszLog != nullptr)
1050 : {
1051 : const bool bAppend =
1052 13 : CPLGetConfigOption("CPL_LOG_APPEND", nullptr) != nullptr;
1053 13 : const char *pszAccess = bAppend ? "at" : "wt";
1054 13 : fpLog = CPLfopenUTF8(pszLog, pszAccess);
1055 13 : if (fpLog == nullptr)
1056 0 : fpLog = stderr;
1057 : }
1058 : }
1059 :
1060 5183 : if (eErrClass == CE_Debug)
1061 : {
1062 : #ifndef _WIN32
1063 1120 : CPLErrorContext *psCtx = CPLGetErrorContext();
1064 1120 : if (psCtx != nullptr && !IS_PREFEFINED_ERROR_CTX(psCtx) &&
1065 2240 : fpLog == stderr && CPLIsInteractive(stderr))
1066 : {
1067 0 : if (psCtx->bProgressMode)
1068 : {
1069 : // Erase the content of the current line
1070 0 : fprintf(stderr, "\r");
1071 0 : fprintf(stderr, "%s", pszErrorMsg);
1072 0 : fflush(stderr);
1073 0 : psCtx->bEmitNewlineBeforeNextDbgMsg = true;
1074 : }
1075 : else
1076 : {
1077 0 : if (psCtx->bEmitNewlineBeforeNextDbgMsg)
1078 : {
1079 0 : psCtx->bEmitNewlineBeforeNextDbgMsg = false;
1080 0 : fprintf(fpLog, "\n");
1081 : }
1082 0 : fprintf(fpLog, "%s\n", pszErrorMsg);
1083 : }
1084 : }
1085 : else
1086 : #endif
1087 : {
1088 1120 : fprintf(fpLog, "%s\n", pszErrorMsg);
1089 : }
1090 : }
1091 4063 : else if (eErrClass == CE_Warning)
1092 3151 : fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
1093 : else
1094 912 : fprintf(fpLog, "ERROR %d%c %s\n", nError, chErrorSeparator,
1095 : pszErrorMsg);
1096 :
1097 5183 : if (eErrClass != CE_Debug && nMaxErrors > 0 && nCount == nMaxErrors)
1098 : {
1099 2 : fprintf(fpLog,
1100 : "More than %d errors or warnings have been reported. "
1101 : "No more will be reported from now.\n",
1102 : nMaxErrors);
1103 : }
1104 :
1105 5183 : fflush(fpLog);
1106 : }
1107 :
1108 : /************************************************************************/
1109 : /* CPLQuietErrorHandler() */
1110 : /************************************************************************/
1111 :
1112 : /** Error handler that does not do anything, except for debug messages. */
1113 43093 : void CPL_STDCALL CPLQuietErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1114 : const char *pszErrorMsg)
1115 :
1116 : {
1117 43093 : if (eErrClass == CE_Debug)
1118 308 : CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
1119 43093 : }
1120 :
1121 : /************************************************************************/
1122 : /* CPLQuietWarningsErrorHandler() */
1123 : /************************************************************************/
1124 :
1125 : /** Error handler that ignores CE_Warning messages. */
1126 7 : void CPL_STDCALL CPLQuietWarningsErrorHandler(CPLErr eErrClass,
1127 : CPLErrorNum nError,
1128 : const char *pszErrorMsg)
1129 :
1130 : {
1131 7 : if (eErrClass != CE_Warning)
1132 2 : CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
1133 7 : }
1134 :
1135 : /************************************************************************/
1136 : /* CPLLoggingErrorHandler() */
1137 : /************************************************************************/
1138 :
1139 : /** Error handler that logs into the file defined by the CPL_LOG configuration
1140 : * option, or stderr otherwise.
1141 : */
1142 0 : void CPL_STDCALL CPLLoggingErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1143 : const char *pszErrorMsg)
1144 :
1145 : {
1146 0 : if (!bLogInit)
1147 : {
1148 0 : bLogInit = true;
1149 :
1150 0 : CPLSetConfigOption("CPL_TIMESTAMP", "ON");
1151 :
1152 0 : const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr);
1153 :
1154 0 : fpLog = stderr;
1155 0 : if (cpl_log != nullptr && EQUAL(cpl_log, "OFF"))
1156 : {
1157 0 : fpLog = nullptr;
1158 : }
1159 0 : else if (cpl_log != nullptr)
1160 : {
1161 0 : size_t nPathLen = strlen(cpl_log) + 20;
1162 0 : char *pszPath = static_cast<char *>(CPLMalloc(nPathLen));
1163 0 : strcpy(pszPath, cpl_log);
1164 :
1165 0 : int i = 0;
1166 0 : while ((fpLog = CPLfopenUTF8(pszPath, "rt")) != nullptr)
1167 : {
1168 0 : fclose(fpLog);
1169 :
1170 : // Generate sequenced log file names, inserting # before ext.
1171 0 : if (strrchr(cpl_log, '.') == nullptr)
1172 : {
1173 0 : snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log, i++,
1174 : ".log");
1175 : }
1176 : else
1177 : {
1178 0 : size_t pos = 0;
1179 0 : char *cpl_log_base = CPLStrdup(cpl_log);
1180 0 : pos = strcspn(cpl_log_base, ".");
1181 0 : if (pos > 0)
1182 : {
1183 0 : cpl_log_base[pos] = '\0';
1184 : }
1185 0 : snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log_base, i++,
1186 : ".log");
1187 0 : CPLFree(cpl_log_base);
1188 : }
1189 : }
1190 :
1191 0 : fpLog = CPLfopenUTF8(pszPath, "wt");
1192 0 : CPLFree(pszPath);
1193 : }
1194 : }
1195 :
1196 0 : if (fpLog == nullptr)
1197 0 : return;
1198 :
1199 0 : if (eErrClass == CE_Debug)
1200 0 : fprintf(fpLog, "%s\n", pszErrorMsg);
1201 0 : else if (eErrClass == CE_Warning)
1202 0 : fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
1203 : else
1204 0 : fprintf(fpLog, "ERROR %d: %s\n", nError, pszErrorMsg);
1205 :
1206 0 : fflush(fpLog);
1207 : }
1208 :
1209 : /**********************************************************************
1210 : * CPLTurnFailureIntoWarning() *
1211 : **********************************************************************/
1212 :
1213 : /** Whether failures should be turned into warnings.
1214 : */
1215 13534 : void CPLTurnFailureIntoWarning(int bOn)
1216 : {
1217 13534 : CPLErrorContext *psCtx = CPLGetErrorContext();
1218 13534 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1219 : {
1220 0 : fprintf(stderr, "CPLTurnFailureIntoWarning() failed.\n");
1221 0 : return;
1222 : }
1223 13534 : psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
1224 13534 : if (psCtx->nFailureIntoWarning < 0)
1225 : {
1226 0 : CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / "
1227 : "CPLTurnFailureIntoWarning(FALSE)");
1228 : }
1229 : }
1230 :
1231 : /**********************************************************************
1232 : * CPLSetErrorHandlerEx() *
1233 : **********************************************************************/
1234 :
1235 : /**
1236 : * Install custom error handle with user's data. This method is
1237 : * essentially CPLSetErrorHandler with an added pointer to pUserData.
1238 : * The pUserData is not returned in the CPLErrorHandler, however, and
1239 : * must be fetched via CPLGetErrorHandlerUserData.
1240 : *
1241 : * @param pfnErrorHandlerNew new error handler function.
1242 : * @param pUserData User data to carry along with the error context.
1243 : * @return returns the previously installed error handler.
1244 : */
1245 :
1246 : CPLErrorHandler CPL_STDCALL
1247 21 : CPLSetErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew, void *pUserData)
1248 : {
1249 21 : CPLErrorContext *psCtx = CPLGetErrorContext();
1250 21 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1251 : {
1252 0 : fprintf(stderr, "CPLSetErrorHandlerEx() failed.\n");
1253 0 : return nullptr;
1254 : }
1255 :
1256 21 : if (psCtx->psHandlerStack != nullptr)
1257 : {
1258 0 : CPLDebug("CPL", "CPLSetErrorHandler() called with an error handler on "
1259 : "the local stack. New error handler will not be used "
1260 : "immediately.");
1261 : }
1262 :
1263 21 : CPLErrorHandler pfnOldHandler = nullptr;
1264 : {
1265 21 : CPLMutexHolderD(&hErrorMutex);
1266 :
1267 21 : pfnOldHandler = pfnErrorHandler;
1268 :
1269 21 : pfnErrorHandler = pfnErrorHandlerNew;
1270 :
1271 21 : pErrorHandlerUserData = pUserData;
1272 : }
1273 :
1274 21 : return pfnOldHandler;
1275 : }
1276 :
1277 : /**********************************************************************
1278 : * CPLSetErrorHandler() *
1279 : **********************************************************************/
1280 :
1281 : /**
1282 : * Install custom error handler.
1283 : *
1284 : * Allow the library's user to specify an error handler function.
1285 : * A valid error handler is a C function with the following prototype:
1286 : *
1287 : * \code{.cpp}
1288 : * void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
1289 : * \endcode
1290 : *
1291 : * Pass NULL to come back to the default behavior. The default behavior
1292 : * (CPLDefaultErrorHandler()) is to write the message to stderr.
1293 : *
1294 : * The msg will be a partially formatted error message not containing the
1295 : * "ERROR %d:" portion emitted by the default handler. Message formatting
1296 : * is handled by CPLError() before calling the handler. If the error
1297 : * handler function is passed a CE_Fatal class error and returns, then
1298 : * CPLError() will call abort(). Applications wanting to interrupt this
1299 : * fatal behavior will have to use longjmp(), or a C++ exception to
1300 : * indirectly exit the function.
1301 : *
1302 : * Another standard error handler is CPLQuietErrorHandler() which doesn't
1303 : * make any attempt to report the passed error or warning messages but
1304 : * will process debug messages via CPLDefaultErrorHandler.
1305 : *
1306 : * Note that error handlers set with CPLSetErrorHandler() apply to all
1307 : * threads in an application, while error handlers set with CPLPushErrorHandler
1308 : * are thread-local. However, any error handlers pushed with
1309 : * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
1310 : * precedence over the global error handlers set with CPLSetErrorHandler().
1311 : * Generally speaking CPLSetErrorHandler() would be used to set a desired
1312 : * global error handler, while CPLPushErrorHandler() would be used to install
1313 : * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
1314 : * error reporting in a limited segment of code.
1315 : *
1316 : * @param pfnErrorHandlerNew new error handler function.
1317 : * @return returns the previously installed error handler.
1318 : */
1319 : CPLErrorHandler CPL_STDCALL
1320 14 : CPLSetErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
1321 : {
1322 14 : return CPLSetErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1323 : }
1324 :
1325 : /************************************************************************/
1326 : /* CPLPushErrorHandler() */
1327 : /************************************************************************/
1328 :
1329 : /**
1330 : * Push a new CPLError handler.
1331 : *
1332 : * This pushes a new error handler on the thread-local error handler
1333 : * stack. This handler will be used until removed with CPLPopErrorHandler().
1334 : *
1335 : * The CPLSetErrorHandler() docs have further information on how
1336 : * CPLError handlers work.
1337 : *
1338 : * @param pfnErrorHandlerNew new error handler function.
1339 : */
1340 :
1341 220599 : void CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
1342 :
1343 : {
1344 220599 : CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1345 220595 : }
1346 :
1347 : /************************************************************************/
1348 : /* CPLPushErrorHandlerEx() */
1349 : /************************************************************************/
1350 :
1351 : /**
1352 : * Push a new CPLError handler with user data on the error context.
1353 : *
1354 : * This pushes a new error handler on the thread-local error handler
1355 : * stack. This handler will be used until removed with CPLPopErrorHandler().
1356 : * Obtain the user data back by using CPLGetErrorContext().
1357 : *
1358 : * The CPLSetErrorHandler() docs have further information on how
1359 : * CPLError handlers work.
1360 : *
1361 : * @param pfnErrorHandlerNew new error handler function.
1362 : * @param pUserData User data to put on the error context.
1363 : */
1364 8423500 : void CPL_STDCALL CPLPushErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,
1365 : void *pUserData)
1366 :
1367 : {
1368 8423500 : CPLErrorContext *psCtx = CPLGetErrorContext();
1369 :
1370 8423440 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1371 : {
1372 27 : fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
1373 0 : return;
1374 : }
1375 :
1376 : CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
1377 8423410 : CPLMalloc(sizeof(CPLErrorHandlerNode)));
1378 8423450 : psNode->psNext = psCtx->psHandlerStack;
1379 8423450 : psNode->pfnHandler = pfnErrorHandlerNew;
1380 8423450 : psNode->pUserData = pUserData;
1381 8423450 : psNode->bCatchDebug = true;
1382 8423450 : psCtx->psHandlerStack = psNode;
1383 : }
1384 :
1385 : /************************************************************************/
1386 : /* CPLPopErrorHandler() */
1387 : /************************************************************************/
1388 :
1389 : /**
1390 : * Pop error handler off stack.
1391 : *
1392 : * Discards the current error handler on the error handler stack, and restores
1393 : * the one in use before the last CPLPushErrorHandler() call. This method
1394 : * has no effect if there are no error handlers on the current threads error
1395 : * handler stack.
1396 : */
1397 :
1398 8423510 : void CPL_STDCALL CPLPopErrorHandler()
1399 :
1400 : {
1401 8423510 : CPLErrorContext *psCtx = CPLGetErrorContext();
1402 :
1403 8423390 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1404 : {
1405 197 : fprintf(stderr, "CPLPopErrorHandler() failed.\n");
1406 0 : return;
1407 : }
1408 :
1409 8423190 : if (psCtx->psHandlerStack != nullptr)
1410 : {
1411 8423280 : CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
1412 :
1413 8423280 : psCtx->psHandlerStack = psNode->psNext;
1414 8423280 : VSIFree(psNode);
1415 : }
1416 : }
1417 :
1418 : /************************************************************************/
1419 : /* CPLCallPreviousHandler() */
1420 : /************************************************************************/
1421 :
1422 : /**
1423 : * Call the previously installed error handler in the error handler stack.
1424 : *
1425 : * Only to be used by a custom error handler that wants to forward events to
1426 : * the previous error handler.
1427 : *
1428 : * @since GDAL 3.8
1429 : */
1430 :
1431 21565 : void CPLCallPreviousHandler(CPLErr eErrClass, CPLErrorNum err_no,
1432 : const char *pszMsg)
1433 : {
1434 21565 : CPLErrorContext *psCtx = CPLGetErrorContext();
1435 :
1436 21565 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1437 : {
1438 0 : fprintf(stderr, "CPLCallPreviousHandler() failed.\n");
1439 0 : return;
1440 : }
1441 :
1442 21565 : if (psCtx->psHandlerStack != nullptr)
1443 : {
1444 21565 : CPLErrorHandlerNode *psCurNode = psCtx->psHandlerStack;
1445 21565 : psCtx->psHandlerStack = psCurNode->psNext;
1446 21565 : if (psCtx->psHandlerStack)
1447 : {
1448 1439 : CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
1449 1439 : psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMsg);
1450 1439 : if (psNewCurNode != psCtx->psHandlerStack)
1451 : {
1452 0 : fprintf(stderr, "CPLCallPreviousHandler() has detected that a "
1453 : "previous error handler messed up with the "
1454 : "error stack. Chaos guaranteed!\n");
1455 : }
1456 : }
1457 : else
1458 20126 : CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
1459 21565 : psCtx->psHandlerStack = psCurNode;
1460 : }
1461 : else
1462 : {
1463 0 : CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
1464 : }
1465 : }
1466 :
1467 : /************************************************************************/
1468 : /* CPLSetCurrentErrorHandlerCatchDebug() */
1469 : /************************************************************************/
1470 :
1471 : /**
1472 : * Set if the current error handler should intercept debug messages, or if
1473 : * they should be processed by the previous handler.
1474 : *
1475 : * By default when installing a custom error handler, this one intercepts
1476 : * debug messages. In some cases, this might not be desirable and the user
1477 : * would prefer that the previous installed handler (or the default one if no
1478 : * previous installed handler exists in the stack) deal with it. In which
1479 : * case, this function should be called with bCatchDebug = FALSE.
1480 : *
1481 : * @param bCatchDebug FALSE if the current error handler should not intercept
1482 : * debug messages
1483 : */
1484 :
1485 95309 : void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)
1486 : {
1487 95309 : CPLErrorContext *psCtx = CPLGetErrorContext();
1488 :
1489 95227 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1490 : {
1491 40 : fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
1492 0 : return;
1493 : }
1494 :
1495 95187 : if (psCtx->psHandlerStack != nullptr)
1496 95202 : psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
1497 : else
1498 0 : gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
1499 : }
1500 :
1501 : /************************************************************************/
1502 : /* _CPLAssert() */
1503 : /* */
1504 : /* This function is called only when an assertion fails. */
1505 : /************************************************************************/
1506 :
1507 : /**
1508 : * Report failure of a logical assertion.
1509 : *
1510 : * Applications would normally use the CPLAssert() macro which expands
1511 : * into code calling _CPLAssert() only if the condition fails. _CPLAssert()
1512 : * will generate a CE_Fatal error call to CPLError(), indicating the file
1513 : * name, and line number of the failed assertion, as well as containing
1514 : * the assertion itself.
1515 : *
1516 : * There is no reason for application code to call _CPLAssert() directly.
1517 : */
1518 :
1519 0 : void CPL_STDCALL _CPLAssert(const char *pszExpression, const char *pszFile,
1520 : int iLine)
1521 :
1522 : {
1523 0 : CPLError(CE_Fatal, CPLE_AssertionFailed,
1524 : "Assertion `%s' failed "
1525 : "in file `%s', line %d",
1526 : pszExpression, pszFile, iLine);
1527 :
1528 : // Just to please compiler so it is aware the function does not return.
1529 0 : abort();
1530 : }
1531 :
1532 : /************************************************************************/
1533 : /* CPLCleanupErrorMutex() */
1534 : /************************************************************************/
1535 :
1536 1570 : void CPLCleanupErrorMutex()
1537 : {
1538 1570 : if (hErrorMutex != nullptr)
1539 : {
1540 185 : CPLDestroyMutex(hErrorMutex);
1541 185 : hErrorMutex = nullptr;
1542 : }
1543 1570 : if (fpLog != nullptr && fpLog != stderr)
1544 : {
1545 1 : fclose(fpLog);
1546 1 : fpLog = nullptr;
1547 1 : bLogInit = false;
1548 : }
1549 1570 : }
1550 :
1551 7482 : bool CPLIsDefaultErrorHandlerAndCatchDebug()
1552 : {
1553 7482 : CPLErrorContext *psCtx = CPLGetErrorContext();
1554 7482 : return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
1555 14964 : gbCatchDebug && pfnErrorHandler == CPLDefaultErrorHandler;
1556 : }
1557 :
1558 : /************************************************************************/
1559 : /* CPLErrorStateBackuper::CPLErrorStateBackuper() */
1560 : /************************************************************************/
1561 :
1562 158585 : CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
1563 158585 : : m_nLastErrorNum(CPLGetLastErrorNo()),
1564 317173 : m_nLastErrorType(CPLGetLastErrorType()),
1565 : m_osLastErrorMsg(CPLGetLastErrorMsg()),
1566 317176 : m_nLastErrorCounter(CPLGetErrorCounter()),
1567 : m_poErrorHandlerPusher(
1568 : hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
1569 158588 : : nullptr)
1570 : {
1571 158583 : }
1572 :
1573 : /************************************************************************/
1574 : /* CPLErrorStateBackuper::~CPLErrorStateBackuper() */
1575 : /************************************************************************/
1576 :
1577 158583 : CPLErrorStateBackuper::~CPLErrorStateBackuper()
1578 : {
1579 158588 : CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
1580 158590 : m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
1581 158586 : }
1582 :
1583 : /*! @cond Doxygen_Suppress */
1584 :
1585 : /************************************************************************/
1586 : /* CPLErrorAccumulator::Context::Context() */
1587 : /************************************************************************/
1588 :
1589 92260 : CPLErrorAccumulator::Context::Context(CPLErrorAccumulator &sAccumulator)
1590 : {
1591 92260 : CPLPushErrorHandlerEx(CPLErrorAccumulator::Accumulator, &sAccumulator);
1592 92283 : CPLSetCurrentErrorHandlerCatchDebug(false);
1593 92205 : }
1594 :
1595 : /************************************************************************/
1596 : /* CPLErrorAccumulator::Context::~Context() */
1597 : /************************************************************************/
1598 :
1599 91995 : CPLErrorAccumulator::Context::~Context()
1600 : {
1601 91995 : CPLPopErrorHandler();
1602 92157 : }
1603 :
1604 : /************************************************************************/
1605 : /* CPLErrorAccumulator::InstallForCurrentScope() */
1606 : /************************************************************************/
1607 :
1608 92307 : CPLErrorAccumulator::Context CPLErrorAccumulator::InstallForCurrentScope()
1609 : {
1610 92307 : return CPLErrorAccumulator::Context(*this);
1611 : }
1612 :
1613 : /************************************************************************/
1614 : /* CPLErrorAccumulator::ReplayErrors() */
1615 : /************************************************************************/
1616 :
1617 340 : void CPLErrorAccumulator::ReplayErrors()
1618 : {
1619 680 : std::lock_guard oLock(mutex);
1620 349 : for (const auto &err : errors)
1621 : {
1622 9 : CPLError(err.type, err.no, "%s", err.msg.c_str());
1623 : }
1624 340 : }
1625 :
1626 : /************************************************************************/
1627 : /* CPLErrorAccumulator::Accumulator() */
1628 : /************************************************************************/
1629 :
1630 451 : /* static */ void CPL_STDCALL CPLErrorAccumulator::Accumulator(CPLErr eErr,
1631 : CPLErrorNum no,
1632 : const char *msg)
1633 : {
1634 451 : if (eErr != CE_Debug)
1635 : {
1636 : CPLErrorAccumulator *pThis =
1637 451 : static_cast<CPLErrorAccumulator *>(CPLGetErrorHandlerUserData());
1638 451 : std::lock_guard oLock(pThis->mutex);
1639 451 : pThis->errors.push_back(
1640 902 : CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
1641 : }
1642 451 : }
1643 :
1644 : /*! @endcond */
|