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 579321 : static char *CPLErrorContextGetString(CPLErrorContext *psCtxt)
96 : {
97 579321 : return psCtxt->szLastErrMsg;
98 : }
99 :
100 : /************************************************************************/
101 : /* CPLGetErrorContext() */
102 : /************************************************************************/
103 :
104 47087300 : static CPLErrorContext *CPLGetErrorContext()
105 :
106 : {
107 47087300 : int bError = FALSE;
108 : CPLErrorContext *psCtx = reinterpret_cast<CPLErrorContext *>(
109 47087300 : CPLGetTLSEx(CTLS_ERRORCONTEXT, &bError));
110 47083200 : if (bError)
111 0 : return nullptr;
112 :
113 47083200 : if (psCtx == nullptr)
114 : {
115 : psCtx = static_cast<CPLErrorContext *>(
116 2880 : VSICalloc(sizeof(CPLErrorContext), 1));
117 2881 : if (psCtx == nullptr)
118 : {
119 0 : fprintf(stderr, "Out of memory attempting to report error.\n");
120 0 : return nullptr;
121 : }
122 2881 : psCtx->eLastErrType = CE_None;
123 2881 : psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
124 2881 : CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
125 : }
126 :
127 47083100 : 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 5909300 : void *CPL_STDCALL CPLGetErrorHandlerUserData(void)
148 : {
149 : // get the current threadlocal or global error context user data
150 5909300 : CPLErrorContext *psCtx = CPLGetErrorContext();
151 5909300 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
152 0 : abort();
153 5909300 : return reinterpret_cast<void *>(psCtx->psHandlerStack
154 5909300 : ? psCtx->psHandlerStack->pUserData
155 5909300 : : 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 98164 : static void ApplyErrorHandler(CPLErrorContext *psCtx, CPLErr eErrClass,
205 : CPLErrorNum err_no, const char *pszMessage)
206 : {
207 98164 : bool bProcessed = false;
208 :
209 98164 : if (psCtx->psHandlerStack != nullptr)
210 : {
211 : // iterate through the threadlocal handler stack
212 58707 : if ((eErrClass != CE_Debug) || psCtx->psHandlerStack->bCatchDebug)
213 : {
214 : // call the error handler
215 58648 : CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
216 58648 : psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMessage);
217 58648 : 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 58646 : bProcessed = true;
224 : }
225 : else
226 : {
227 : // need to iterate to a parent handler for debug messages
228 59 : CPLErrorHandlerNode *psNode = psCtx->psHandlerStack->psNext;
229 59 : while (psNode != nullptr)
230 : {
231 58 : if (psNode->bCatchDebug)
232 : {
233 58 : CPLErrorHandlerNode *psBackupCurNode =
234 : psCtx->psHandlerStack;
235 58 : psCtx->psHandlerStack = psNode;
236 58 : CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
237 58 : psNode->pfnHandler(eErrClass, err_no, pszMessage);
238 : // cppcheck-suppress knownConditionTrueFalse
239 58 : 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 58 : psCtx->psHandlerStack = psBackupCurNode;
247 58 : bProcessed = true;
248 58 : break;
249 : }
250 0 : psNode = psNode->psNext;
251 : }
252 : }
253 : }
254 :
255 98162 : if (!bProcessed)
256 : {
257 : // hit the global error handler
258 78916 : CPLMutexHolderD(&hErrorMutex);
259 39458 : if ((eErrClass != CE_Debug) || gbCatchDebug)
260 : {
261 39456 : if (pfnErrorHandler != nullptr)
262 : {
263 39454 : 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 98162 : }
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 96507 : 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 96507 : va_start(args, fmt);
317 96507 : CPLErrorV(eErrClass, err_no, fmt, args);
318 96527 : va_end(args);
319 96527 : }
320 :
321 : /************************************************************************/
322 : /* CPLErrorV() */
323 : /************************************************************************/
324 :
325 : /** Same as CPLError() but with a va_list */
326 97409 : void CPLErrorV(CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
327 : va_list args)
328 : {
329 97409 : CPLErrorContext *psCtx = CPLGetErrorContext();
330 97381 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
331 : {
332 7 : int bMemoryError = FALSE;
333 7 : 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 7 : 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 7 : char szShortMessage[80] = {};
353 7 : 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 97374 : if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
362 2 : 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 97374 : 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 97374 : int nPreviousSize = 0;
384 155958 : if (psCtx->psHandlerStack != nullptr &&
385 58503 : 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 97455 : int nPR = 0;
407 13 : while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
408 97468 : psCtx->nLastErrMsgMax - nPreviousSize, fmt,
409 97365 : wrk_args)) == -1 ||
410 97454 : nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
411 51 : psCtx->nLastErrMsgMax < 1000000)
412 : {
413 : #ifdef va_copy
414 13 : va_end(wrk_args);
415 13 : va_copy(wrk_args, args);
416 : #else
417 : wrk_args = args;
418 : #endif
419 13 : psCtx->nLastErrMsgMax *= 3;
420 26 : psCtx = static_cast<CPLErrorContext *>(CPLRealloc(
421 : psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
422 13 : psCtx->nLastErrMsgMax + 1));
423 13 : CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
424 : }
425 :
426 97390 : 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 97390 : char *pszPassword = strstr(psCtx->szLastErrMsg, "password=");
437 97390 : 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 97390 : psCtx->nLastErrNo = err_no;
452 97390 : psCtx->eLastErrType = eErrClass;
453 97390 : if (psCtx->nErrorCounter == ~(0U))
454 0 : psCtx->nErrorCounter = 0;
455 : else
456 97390 : psCtx->nErrorCounter++;
457 :
458 97390 : if (CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr)
459 0 : CPLDebug("CPLError", "%s", psCtx->szLastErrMsg);
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Invoke the current error handler. */
463 : /* -------------------------------------------------------------------- */
464 97433 : ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
465 :
466 97432 : 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 621663 : static void CPLvDebug(const char *pszCategory,
583 : CPL_FORMAT_STRING(const char *pszFormat), va_list args)
584 : {
585 621663 : CPLErrorContext *psCtx = CPLGetErrorContext();
586 621629 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
587 2 : return;
588 621627 : const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
589 :
590 : /* -------------------------------------------------------------------- */
591 : /* Does this message pass our current criteria? */
592 : /* -------------------------------------------------------------------- */
593 621778 : if (pszDebug == nullptr || EQUAL(pszDebug, "NO") ||
594 814 : EQUAL(pszDebug, "OFF") || EQUAL(pszDebug, "FALSE") ||
595 795 : EQUAL(pszDebug, "0"))
596 : {
597 620984 : return;
598 : }
599 :
600 794 : if (!EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, "YES") &&
601 112 : !EQUAL(pszDebug, "TRUE") && !EQUAL(pszDebug, "1") &&
602 106 : !EQUAL(pszDebug, ""))
603 : {
604 : // check if value of CPL_DEBUG contains the category
605 105 : const size_t nLen = strlen(pszCategory);
606 :
607 105 : size_t i = 0;
608 759 : for (i = 0; pszDebug[i] != '\0'; i++)
609 : {
610 696 : if (EQUALN(pszCategory, pszDebug + i, nLen))
611 42 : break;
612 : }
613 :
614 105 : if (pszDebug[i] == '\0')
615 63 : return;
616 : }
617 :
618 : /* -------------------------------------------------------------------- */
619 : /* Allocate a block for the error. */
620 : /* -------------------------------------------------------------------- */
621 731 : const int ERROR_MAX = 25000;
622 731 : char *pszMessage = static_cast<char *>(VSIMalloc(ERROR_MAX));
623 731 : 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 731 : pszMessage[0] = '\0';
632 : #ifdef TIMESTAMP_DEBUG
633 731 : if (CPLTestBool(CPLGetConfigOption("CPL_TIMESTAMP", "NO")))
634 : {
635 : static struct CPLTimeVal tvStart;
636 4 : static const auto unused = CPLGettimeofday(&tvStart, nullptr);
637 4 : CPL_IGNORE_RET_VAL(unused);
638 : struct CPLTimeVal tv;
639 4 : CPLGettimeofday(&tv, nullptr);
640 4 : strcpy(pszMessage, "[");
641 4 : 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 4 : if (pszMessage[strlen(pszMessage) - 1] == '\n')
648 : {
649 4 : pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
650 : }
651 4 : CPLsnprintf(pszMessage + strlen(pszMessage),
652 4 : ERROR_MAX - strlen(pszMessage),
653 4 : "].%04d, %03.04f: ", static_cast<int>(tv.tv_usec / 100),
654 4 : tv.tv_sec + tv.tv_usec * 1e-6 -
655 4 : (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 731 : strcat(pszMessage, pszCategory);
672 731 : strcat(pszMessage, ": ");
673 :
674 : /* -------------------------------------------------------------------- */
675 : /* Format the application provided portion of the debug message. */
676 : /* -------------------------------------------------------------------- */
677 731 : CPLvsnprintf(pszMessage + strlen(pszMessage),
678 731 : ERROR_MAX - strlen(pszMessage), pszFormat, args);
679 :
680 : /* -------------------------------------------------------------------- */
681 : /* Obfuscate any password in error message */
682 : /* -------------------------------------------------------------------- */
683 :
684 731 : char *pszPassword = strstr(pszMessage, "password=");
685 731 : 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 731 : ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
699 :
700 731 : 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 621724 : void CPLDebug(const char *pszCategory, CPL_FORMAT_STRING(const char *pszFormat),
735 : ...)
736 :
737 : {
738 : va_list args;
739 621724 : va_start(args, pszFormat);
740 621724 : CPLvDebug(pszCategory, pszFormat, args);
741 621776 : va_end(args);
742 621776 : }
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 6613940 : void CPL_STDCALL CPLErrorReset()
810 : {
811 6613940 : CPLErrorContext *psCtx = CPLGetErrorContext();
812 6613940 : if (psCtx == nullptr)
813 0 : return;
814 6613940 : if (IS_PREFEFINED_ERROR_CTX(psCtx))
815 : {
816 0 : int bMemoryError = FALSE;
817 0 : CPLSetTLSWithFreeFuncEx(
818 : CTLS_ERRORCONTEXT,
819 : reinterpret_cast<void *>(
820 : const_cast<CPLErrorContext *>(&sNoErrorContext)),
821 : nullptr, &bMemoryError);
822 0 : return;
823 : }
824 :
825 6613940 : psCtx->nLastErrNo = CPLE_None;
826 6613940 : psCtx->szLastErrMsg[0] = '\0';
827 6613940 : psCtx->eLastErrType = CE_None;
828 6613940 : psCtx->nErrorCounter = 0;
829 : }
830 :
831 : /**********************************************************************
832 : * CPLErrorSetState()
833 : **********************************************************************/
834 :
835 579327 : static void CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
836 : const char *pszMsg, GUInt32 *pnErrorCounter)
837 : {
838 579327 : CPLErrorContext *psCtx = CPLGetErrorContext();
839 579326 : if (psCtx == nullptr)
840 0 : return;
841 579326 : if (IS_PREFEFINED_ERROR_CTX(psCtx))
842 : {
843 1 : int bMemoryError = FALSE;
844 1 : if (eErrClass == CE_None)
845 0 : CPLSetTLSWithFreeFuncEx(
846 : CTLS_ERRORCONTEXT,
847 : reinterpret_cast<void *>(
848 : const_cast<CPLErrorContext *>(&sNoErrorContext)),
849 : nullptr, &bMemoryError);
850 1 : else if (eErrClass == CE_Warning)
851 0 : CPLSetTLSWithFreeFuncEx(
852 : CTLS_ERRORCONTEXT,
853 : reinterpret_cast<void *>(
854 : const_cast<CPLErrorContext *>(&sWarningContext)),
855 : nullptr, &bMemoryError);
856 1 : 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 579325 : psCtx->nLastErrNo = err_no;
866 1158650 : const size_t size = std::min(static_cast<size_t>(psCtx->nLastErrMsgMax - 1),
867 579325 : strlen(pszMsg));
868 579321 : char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
869 579321 : memcpy(pszLastErrMsg, pszMsg, size);
870 579321 : pszLastErrMsg[size] = '\0';
871 579321 : psCtx->eLastErrType = eErrClass;
872 579321 : if (pnErrorCounter)
873 100982 : 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 : * @since GDAL 2.0
883 : */
884 :
885 478342 : void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
886 : const char *pszMsg)
887 : {
888 478342 : CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
889 478342 : }
890 :
891 : /**********************************************************************
892 : * CPLGetLastErrorNo()
893 : **********************************************************************/
894 :
895 : /**
896 : * Fetch the last error number.
897 : *
898 : * Fetches the last error number posted with CPLError(), that hasn't
899 : * been cleared by CPLErrorReset(). This is the error number, not the error
900 : * class.
901 : *
902 : * @return the error number of the last error to occur, or CPLE_None (0)
903 : * if there are no posted errors.
904 : */
905 :
906 823320 : CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
907 : {
908 823320 : CPLErrorContext *psCtx = CPLGetErrorContext();
909 821850 : if (psCtx == nullptr)
910 0 : return 0;
911 :
912 821850 : return psCtx->nLastErrNo;
913 : }
914 :
915 : /**********************************************************************
916 : * CPLGetLastErrorType()
917 : **********************************************************************/
918 :
919 : /**
920 : * Fetch the last error type.
921 : *
922 : * Fetches the last error type posted with CPLError(), that hasn't
923 : * been cleared by CPLErrorReset(). This is the error class, not the error
924 : * number.
925 : *
926 : * @return the error type of the last error to occur, or CE_None (0)
927 : * if there are no posted errors.
928 : */
929 :
930 9301070 : CPLErr CPL_STDCALL CPLGetLastErrorType()
931 : {
932 9301070 : CPLErrorContext *psCtx = CPLGetErrorContext();
933 9301070 : if (psCtx == nullptr)
934 0 : return CE_None;
935 :
936 9301070 : return psCtx->eLastErrType;
937 : }
938 :
939 : /**********************************************************************
940 : * CPLGetLastErrorMsg()
941 : **********************************************************************/
942 :
943 : /**
944 : * Get the last error message.
945 : *
946 : * Fetches the last error message posted with CPLError(), that hasn't
947 : * been cleared by CPLErrorReset(). The returned pointer is to an internal
948 : * string that should not be altered or freed.
949 : *
950 : * @return the last error message, or an empty string ("") if there is no
951 : * posted error message.
952 : */
953 :
954 338652 : const char *CPL_STDCALL CPLGetLastErrorMsg()
955 : {
956 338652 : CPLErrorContext *psCtx = CPLGetErrorContext();
957 338653 : if (psCtx == nullptr)
958 0 : return "";
959 :
960 338653 : return psCtx->szLastErrMsg;
961 : }
962 :
963 : /**********************************************************************
964 : * CPLGetErrorCounter()
965 : **********************************************************************/
966 :
967 : /**
968 : * Get the error counter
969 : *
970 : * Fetches the number of errors emitted in the current error context,
971 : * since the last call to CPLErrorReset()
972 : *
973 : * @return the error counter.
974 : * @since GDAL 2.3
975 : */
976 :
977 10494300 : GUInt32 CPL_STDCALL CPLGetErrorCounter()
978 : {
979 10494300 : CPLErrorContext *psCtx = CPLGetErrorContext();
980 10490300 : if (psCtx == nullptr)
981 0 : return 0;
982 :
983 10490300 : return psCtx->nErrorCounter;
984 : }
985 :
986 : /************************************************************************/
987 : /* CPLDefaultErrorHandler() */
988 : /************************************************************************/
989 :
990 : static FILE *fpLog = stderr;
991 : static bool bLogInit = false;
992 :
993 1 : static FILE *CPLfopenUTF8(const char *pszFilename, const char *pszAccess)
994 : {
995 : FILE *f;
996 : #ifdef _WIN32
997 : wchar_t *pwszFilename =
998 : CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
999 : wchar_t *pwszAccess =
1000 : CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
1001 : f = _wfopen(pwszFilename, pwszAccess);
1002 : VSIFree(pwszFilename);
1003 : VSIFree(pwszAccess);
1004 : #else
1005 1 : f = fopen(pszFilename, pszAccess);
1006 : #endif
1007 1 : return f;
1008 : }
1009 :
1010 : /** Default error handler. */
1011 58432 : void CPL_STDCALL CPLDefaultErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1012 : const char *pszErrorMsg)
1013 :
1014 : {
1015 : static int nCount = 0;
1016 : static int nMaxErrors = -1;
1017 : static const char *pszErrorSeparator = ":";
1018 :
1019 58432 : if (eErrClass != CE_Debug)
1020 : {
1021 57820 : if (nMaxErrors == -1)
1022 : {
1023 212 : nMaxErrors =
1024 212 : atoi(CPLGetConfigOption("CPL_MAX_ERROR_REPORTS", "1000"));
1025 : // If running GDAL as a CustomBuild Command os MSBuild, "ERROR bla:"
1026 : // is considered as failing the job. This is rarely the intended
1027 : // behavior
1028 212 : pszErrorSeparator = CPLGetConfigOption("CPL_ERROR_SEPARATOR", ":");
1029 : }
1030 :
1031 57820 : nCount++;
1032 57820 : if (nCount > nMaxErrors && nMaxErrors > 0)
1033 54440 : return;
1034 : }
1035 :
1036 3992 : if (!bLogInit)
1037 : {
1038 225 : bLogInit = true;
1039 :
1040 225 : fpLog = stderr;
1041 225 : const char *pszLog = CPLGetConfigOption("CPL_LOG", nullptr);
1042 225 : if (pszLog != nullptr)
1043 : {
1044 : const bool bAppend =
1045 1 : CPLGetConfigOption("CPL_LOG_APPEND", nullptr) != nullptr;
1046 1 : const char *pszAccess = bAppend ? "at" : "wt";
1047 1 : fpLog = CPLfopenUTF8(pszLog, pszAccess);
1048 1 : if (fpLog == nullptr)
1049 0 : fpLog = stderr;
1050 : }
1051 : }
1052 :
1053 3992 : if (eErrClass == CE_Debug)
1054 : {
1055 : #ifndef _WIN32
1056 612 : CPLErrorContext *psCtx = CPLGetErrorContext();
1057 612 : if (psCtx != nullptr && !IS_PREFEFINED_ERROR_CTX(psCtx) &&
1058 1224 : fpLog == stderr && CPLIsInteractive(stderr))
1059 : {
1060 0 : if (psCtx->bProgressMode)
1061 : {
1062 : // Erase the content of the current line
1063 0 : fprintf(stderr, "\r");
1064 0 : fprintf(stderr, "%s", pszErrorMsg);
1065 0 : fflush(stderr);
1066 0 : psCtx->bEmitNewlineBeforeNextDbgMsg = true;
1067 : }
1068 : else
1069 : {
1070 0 : if (psCtx->bEmitNewlineBeforeNextDbgMsg)
1071 : {
1072 0 : psCtx->bEmitNewlineBeforeNextDbgMsg = false;
1073 0 : fprintf(fpLog, "\n");
1074 : }
1075 0 : fprintf(fpLog, "%s\n", pszErrorMsg);
1076 : }
1077 : }
1078 : else
1079 : #endif
1080 : {
1081 612 : fprintf(fpLog, "%s\n", pszErrorMsg);
1082 : }
1083 : }
1084 3380 : else if (eErrClass == CE_Warning)
1085 2574 : fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
1086 : else
1087 806 : fprintf(fpLog, "ERROR %d%s %s\n", nError, pszErrorSeparator,
1088 : pszErrorMsg);
1089 :
1090 3992 : if (eErrClass != CE_Debug && nMaxErrors > 0 && nCount == nMaxErrors)
1091 : {
1092 2 : fprintf(fpLog,
1093 : "More than %d errors or warnings have been reported. "
1094 : "No more will be reported from now.\n",
1095 : nMaxErrors);
1096 : }
1097 :
1098 3992 : fflush(fpLog);
1099 : }
1100 :
1101 : /************************************************************************/
1102 : /* CPLQuietErrorHandler() */
1103 : /************************************************************************/
1104 :
1105 : /** Error handler that does not do anything, except for debug messages. */
1106 37039 : void CPL_STDCALL CPLQuietErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1107 : const char *pszErrorMsg)
1108 :
1109 : {
1110 37039 : if (eErrClass == CE_Debug)
1111 2 : CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
1112 37039 : }
1113 :
1114 : /************************************************************************/
1115 : /* CPLLoggingErrorHandler() */
1116 : /************************************************************************/
1117 :
1118 : /** Error handler that logs into the file defined by the CPL_LOG configuration
1119 : * option, or stderr otherwise.
1120 : */
1121 0 : void CPL_STDCALL CPLLoggingErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1122 : const char *pszErrorMsg)
1123 :
1124 : {
1125 0 : if (!bLogInit)
1126 : {
1127 0 : bLogInit = true;
1128 :
1129 0 : CPLSetConfigOption("CPL_TIMESTAMP", "ON");
1130 :
1131 0 : const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr);
1132 :
1133 0 : fpLog = stderr;
1134 0 : if (cpl_log != nullptr && EQUAL(cpl_log, "OFF"))
1135 : {
1136 0 : fpLog = nullptr;
1137 : }
1138 0 : else if (cpl_log != nullptr)
1139 : {
1140 0 : size_t nPathLen = strlen(cpl_log) + 20;
1141 0 : char *pszPath = static_cast<char *>(CPLMalloc(nPathLen));
1142 0 : strcpy(pszPath, cpl_log);
1143 :
1144 0 : int i = 0;
1145 0 : while ((fpLog = CPLfopenUTF8(pszPath, "rt")) != nullptr)
1146 : {
1147 0 : fclose(fpLog);
1148 :
1149 : // Generate sequenced log file names, inserting # before ext.
1150 0 : if (strrchr(cpl_log, '.') == nullptr)
1151 : {
1152 0 : snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log, i++,
1153 : ".log");
1154 : }
1155 : else
1156 : {
1157 0 : size_t pos = 0;
1158 0 : char *cpl_log_base = CPLStrdup(cpl_log);
1159 0 : pos = strcspn(cpl_log_base, ".");
1160 0 : if (pos > 0)
1161 : {
1162 0 : cpl_log_base[pos] = '\0';
1163 : }
1164 0 : snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log_base, i++,
1165 : ".log");
1166 0 : CPLFree(cpl_log_base);
1167 : }
1168 : }
1169 :
1170 0 : fpLog = CPLfopenUTF8(pszPath, "wt");
1171 0 : CPLFree(pszPath);
1172 : }
1173 : }
1174 :
1175 0 : if (fpLog == nullptr)
1176 0 : return;
1177 :
1178 0 : if (eErrClass == CE_Debug)
1179 0 : fprintf(fpLog, "%s\n", pszErrorMsg);
1180 0 : else if (eErrClass == CE_Warning)
1181 0 : fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
1182 : else
1183 0 : fprintf(fpLog, "ERROR %d: %s\n", nError, pszErrorMsg);
1184 :
1185 0 : fflush(fpLog);
1186 : }
1187 :
1188 : /**********************************************************************
1189 : * CPLTurnFailureIntoWarning() *
1190 : **********************************************************************/
1191 :
1192 : /** Whether failures should be turned into warnings.
1193 : */
1194 1370 : void CPLTurnFailureIntoWarning(int bOn)
1195 : {
1196 1370 : CPLErrorContext *psCtx = CPLGetErrorContext();
1197 1370 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1198 : {
1199 0 : fprintf(stderr, "CPLTurnFailureIntoWarning() failed.\n");
1200 0 : return;
1201 : }
1202 1370 : psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
1203 1370 : if (psCtx->nFailureIntoWarning < 0)
1204 : {
1205 0 : CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / "
1206 : "CPLTurnFailureIntoWarning(FALSE)");
1207 : }
1208 : }
1209 :
1210 : /**********************************************************************
1211 : * CPLSetErrorHandlerEx() *
1212 : **********************************************************************/
1213 :
1214 : /**
1215 : * Install custom error handle with user's data. This method is
1216 : * essentially CPLSetErrorHandler with an added pointer to pUserData.
1217 : * The pUserData is not returned in the CPLErrorHandler, however, and
1218 : * must be fetched via CPLGetErrorHandlerUserData.
1219 : *
1220 : * @param pfnErrorHandlerNew new error handler function.
1221 : * @param pUserData User data to carry along with the error context.
1222 : * @return returns the previously installed error handler.
1223 : */
1224 :
1225 : CPLErrorHandler CPL_STDCALL
1226 14 : CPLSetErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew, void *pUserData)
1227 : {
1228 14 : CPLErrorContext *psCtx = CPLGetErrorContext();
1229 14 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1230 : {
1231 0 : fprintf(stderr, "CPLSetErrorHandlerEx() failed.\n");
1232 0 : return nullptr;
1233 : }
1234 :
1235 14 : if (psCtx->psHandlerStack != nullptr)
1236 : {
1237 0 : CPLDebug("CPL", "CPLSetErrorHandler() called with an error handler on "
1238 : "the local stack. New error handler will not be used "
1239 : "immediately.");
1240 : }
1241 :
1242 14 : CPLErrorHandler pfnOldHandler = nullptr;
1243 : {
1244 14 : CPLMutexHolderD(&hErrorMutex);
1245 :
1246 14 : pfnOldHandler = pfnErrorHandler;
1247 :
1248 14 : pfnErrorHandler = pfnErrorHandlerNew;
1249 :
1250 14 : pErrorHandlerUserData = pUserData;
1251 : }
1252 :
1253 14 : return pfnOldHandler;
1254 : }
1255 :
1256 : /**********************************************************************
1257 : * CPLSetErrorHandler() *
1258 : **********************************************************************/
1259 :
1260 : /**
1261 : * Install custom error handler.
1262 : *
1263 : * Allow the library's user to specify an error handler function.
1264 : * A valid error handler is a C function with the following prototype:
1265 : *
1266 : * <pre>
1267 : * void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
1268 : * </pre>
1269 : *
1270 : * Pass NULL to come back to the default behavior. The default behavior
1271 : * (CPLDefaultErrorHandler()) is to write the message to stderr.
1272 : *
1273 : * The msg will be a partially formatted error message not containing the
1274 : * "ERROR %d:" portion emitted by the default handler. Message formatting
1275 : * is handled by CPLError() before calling the handler. If the error
1276 : * handler function is passed a CE_Fatal class error and returns, then
1277 : * CPLError() will call abort(). Applications wanting to interrupt this
1278 : * fatal behavior will have to use longjmp(), or a C++ exception to
1279 : * indirectly exit the function.
1280 : *
1281 : * Another standard error handler is CPLQuietErrorHandler() which doesn't
1282 : * make any attempt to report the passed error or warning messages but
1283 : * will process debug messages via CPLDefaultErrorHandler.
1284 : *
1285 : * Note that error handlers set with CPLSetErrorHandler() apply to all
1286 : * threads in an application, while error handlers set with CPLPushErrorHandler
1287 : * are thread-local. However, any error handlers pushed with
1288 : * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
1289 : * precedence over the global error handlers set with CPLSetErrorHandler().
1290 : * Generally speaking CPLSetErrorHandler() would be used to set a desired
1291 : * global error handler, while CPLPushErrorHandler() would be used to install
1292 : * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
1293 : * error reporting in a limited segment of code.
1294 : *
1295 : * @param pfnErrorHandlerNew new error handler function.
1296 : * @return returns the previously installed error handler.
1297 : */
1298 : CPLErrorHandler CPL_STDCALL
1299 8 : CPLSetErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
1300 : {
1301 8 : return CPLSetErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1302 : }
1303 :
1304 : /************************************************************************/
1305 : /* CPLPushErrorHandler() */
1306 : /************************************************************************/
1307 :
1308 : /**
1309 : * Push a new CPLError handler.
1310 : *
1311 : * This pushes a new error handler on the thread-local error handler
1312 : * stack. This handler will be used until removed with CPLPopErrorHandler().
1313 : *
1314 : * The CPLSetErrorHandler() docs have further information on how
1315 : * CPLError handlers work.
1316 : *
1317 : * @param pfnErrorHandlerNew new error handler function.
1318 : */
1319 :
1320 160711 : void CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
1321 :
1322 : {
1323 160711 : CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1324 160707 : }
1325 :
1326 : /************************************************************************/
1327 : /* CPLPushErrorHandlerEx() */
1328 : /************************************************************************/
1329 :
1330 : /**
1331 : * Push a new CPLError handler with user data on the error context.
1332 : *
1333 : * This pushes a new error handler on the thread-local error handler
1334 : * stack. This handler will be used until removed with CPLPopErrorHandler().
1335 : * Obtain the user data back by using CPLGetErrorContext().
1336 : *
1337 : * The CPLSetErrorHandler() docs have further information on how
1338 : * CPLError handlers work.
1339 : *
1340 : * @param pfnErrorHandlerNew new error handler function.
1341 : * @param pUserData User data to put on the error context.
1342 : */
1343 6130790 : void CPL_STDCALL CPLPushErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,
1344 : void *pUserData)
1345 :
1346 : {
1347 6130790 : CPLErrorContext *psCtx = CPLGetErrorContext();
1348 :
1349 6130750 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1350 : {
1351 8 : fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
1352 0 : return;
1353 : }
1354 :
1355 : CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
1356 6130740 : CPLMalloc(sizeof(CPLErrorHandlerNode)));
1357 6130770 : psNode->psNext = psCtx->psHandlerStack;
1358 6130770 : psNode->pfnHandler = pfnErrorHandlerNew;
1359 6130770 : psNode->pUserData = pUserData;
1360 6130770 : psNode->bCatchDebug = true;
1361 6130770 : psCtx->psHandlerStack = psNode;
1362 : }
1363 :
1364 : /************************************************************************/
1365 : /* CPLPopErrorHandler() */
1366 : /************************************************************************/
1367 :
1368 : /**
1369 : * Pop error handler off stack.
1370 : *
1371 : * Discards the current error handler on the error handler stack, and restores
1372 : * the one in use before the last CPLPushErrorHandler() call. This method
1373 : * has no effect if there are no error handlers on the current threads error
1374 : * handler stack.
1375 : */
1376 :
1377 6130770 : void CPL_STDCALL CPLPopErrorHandler()
1378 :
1379 : {
1380 6130770 : CPLErrorContext *psCtx = CPLGetErrorContext();
1381 :
1382 6130700 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1383 : {
1384 14 : fprintf(stderr, "CPLPopErrorHandler() failed.\n");
1385 0 : return;
1386 : }
1387 :
1388 6130690 : if (psCtx->psHandlerStack != nullptr)
1389 : {
1390 6130760 : CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
1391 :
1392 6130760 : psCtx->psHandlerStack = psNode->psNext;
1393 6130760 : VSIFree(psNode);
1394 : }
1395 : }
1396 :
1397 : /************************************************************************/
1398 : /* CPLCallPreviousHandler() */
1399 : /************************************************************************/
1400 :
1401 : /**
1402 : * Call the previously installed error handler in the error handler stack.
1403 : *
1404 : * Only to be used by a custom error handler that wants to forward events to
1405 : * the previous error handler.
1406 : *
1407 : * @since GDAL 3.8
1408 : */
1409 :
1410 19655 : void CPLCallPreviousHandler(CPLErr eErrClass, CPLErrorNum err_no,
1411 : const char *pszMsg)
1412 : {
1413 19655 : CPLErrorContext *psCtx = CPLGetErrorContext();
1414 :
1415 19655 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1416 : {
1417 0 : fprintf(stderr, "CPLCallPreviousHandler() failed.\n");
1418 0 : return;
1419 : }
1420 :
1421 19655 : if (psCtx->psHandlerStack != nullptr)
1422 : {
1423 19655 : CPLErrorHandlerNode *psCurNode = psCtx->psHandlerStack;
1424 19655 : psCtx->psHandlerStack = psCurNode->psNext;
1425 19655 : if (psCtx->psHandlerStack)
1426 : {
1427 663 : CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
1428 663 : psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMsg);
1429 663 : if (psNewCurNode != psCtx->psHandlerStack)
1430 : {
1431 0 : fprintf(stderr, "CPLCallPreviousHandler() has detected that a "
1432 : "previous error handler messed up with the "
1433 : "error stack. Chaos guaranteed!\n");
1434 : }
1435 : }
1436 : else
1437 18992 : CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
1438 19655 : psCtx->psHandlerStack = psCurNode;
1439 : }
1440 : else
1441 : {
1442 0 : CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
1443 : }
1444 : }
1445 :
1446 : /************************************************************************/
1447 : /* CPLSetCurrentErrorHandlerCatchDebug() */
1448 : /************************************************************************/
1449 :
1450 : /**
1451 : * Set if the current error handler should intercept debug messages, or if
1452 : * they should be processed by the previous handler.
1453 : *
1454 : * By default when installing a custom error handler, this one intercepts
1455 : * debug messages. In some cases, this might not be desirable and the user
1456 : * would prefer that the previous installed handler (or the default one if no
1457 : * previous installed handler exists in the stack) deal with it. In which
1458 : * case, this function should be called with bCatchDebug = FALSE.
1459 : *
1460 : * @param bCatchDebug FALSE if the current error handler should not intercept
1461 : * debug messages
1462 : * @since GDAL 2.1
1463 : */
1464 :
1465 21757 : void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)
1466 : {
1467 21757 : CPLErrorContext *psCtx = CPLGetErrorContext();
1468 :
1469 21735 : if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1470 : {
1471 36 : fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
1472 0 : return;
1473 : }
1474 :
1475 21699 : if (psCtx->psHandlerStack != nullptr)
1476 21707 : psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
1477 : else
1478 0 : gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
1479 : }
1480 :
1481 : /************************************************************************/
1482 : /* _CPLAssert() */
1483 : /* */
1484 : /* This function is called only when an assertion fails. */
1485 : /************************************************************************/
1486 :
1487 : /**
1488 : * Report failure of a logical assertion.
1489 : *
1490 : * Applications would normally use the CPLAssert() macro which expands
1491 : * into code calling _CPLAssert() only if the condition fails. _CPLAssert()
1492 : * will generate a CE_Fatal error call to CPLError(), indicating the file
1493 : * name, and line number of the failed assertion, as well as containing
1494 : * the assertion itself.
1495 : *
1496 : * There is no reason for application code to call _CPLAssert() directly.
1497 : */
1498 :
1499 0 : void CPL_STDCALL _CPLAssert(const char *pszExpression, const char *pszFile,
1500 : int iLine)
1501 :
1502 : {
1503 0 : CPLError(CE_Fatal, CPLE_AssertionFailed,
1504 : "Assertion `%s' failed "
1505 : "in file `%s', line %d",
1506 : pszExpression, pszFile, iLine);
1507 :
1508 : // Just to please compiler so it is aware the function does not return.
1509 0 : abort();
1510 : }
1511 :
1512 : /************************************************************************/
1513 : /* CPLCleanupErrorMutex() */
1514 : /************************************************************************/
1515 :
1516 1371 : void CPLCleanupErrorMutex()
1517 : {
1518 1371 : if (hErrorMutex != nullptr)
1519 : {
1520 194 : CPLDestroyMutex(hErrorMutex);
1521 194 : hErrorMutex = nullptr;
1522 : }
1523 1371 : if (fpLog != nullptr && fpLog != stderr)
1524 : {
1525 1 : fclose(fpLog);
1526 1 : fpLog = nullptr;
1527 1 : bLogInit = false;
1528 : }
1529 1371 : }
1530 :
1531 4825 : bool CPLIsDefaultErrorHandlerAndCatchDebug()
1532 : {
1533 4825 : CPLErrorContext *psCtx = CPLGetErrorContext();
1534 4825 : return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
1535 9650 : gbCatchDebug && pfnErrorHandler == CPLDefaultErrorHandler;
1536 : }
1537 :
1538 : /************************************************************************/
1539 : /* CPLErrorHandlerAccumulator() */
1540 : /************************************************************************/
1541 :
1542 351 : static void CPL_STDCALL CPLErrorHandlerAccumulator(CPLErr eErr, CPLErrorNum no,
1543 : const char *msg)
1544 : {
1545 : std::vector<CPLErrorHandlerAccumulatorStruct> *paoErrors =
1546 : static_cast<std::vector<CPLErrorHandlerAccumulatorStruct> *>(
1547 351 : CPLGetErrorHandlerUserData());
1548 351 : paoErrors->push_back(CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
1549 351 : }
1550 :
1551 76781 : void CPLInstallErrorHandlerAccumulator(
1552 : std::vector<CPLErrorHandlerAccumulatorStruct> &aoErrors)
1553 : {
1554 76781 : CPLPushErrorHandlerEx(CPLErrorHandlerAccumulator, &aoErrors);
1555 76783 : }
1556 :
1557 76793 : void CPLUninstallErrorHandlerAccumulator()
1558 : {
1559 76793 : CPLPopErrorHandler();
1560 76745 : }
1561 :
1562 : /************************************************************************/
1563 : /* CPLErrorStateBackuper::CPLErrorStateBackuper() */
1564 : /************************************************************************/
1565 :
1566 100988 : CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
1567 100988 : : m_nLastErrorNum(CPLGetLastErrorNo()),
1568 201971 : m_nLastErrorType(CPLGetLastErrorType()),
1569 : m_osLastErrorMsg(CPLGetLastErrorMsg()),
1570 201971 : m_nLastErrorCounter(CPLGetErrorCounter()),
1571 : m_poErrorHandlerPusher(
1572 : hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
1573 100986 : : nullptr)
1574 : {
1575 100982 : }
1576 :
1577 : /************************************************************************/
1578 : /* CPLErrorStateBackuper::~CPLErrorStateBackuper() */
1579 : /************************************************************************/
1580 :
1581 100980 : CPLErrorStateBackuper::~CPLErrorStateBackuper()
1582 : {
1583 100986 : CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
1584 : m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
1585 100982 : }
|