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