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