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 #include <cstdarg>
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cstring>
38
39 #include <algorithm>
40
41 #include "cpl_config.h"
42 #include "cpl_conv.h"
43 #include "cpl_multiproc.h"
44 #include "cpl_string.h"
45 #include "cpl_vsi.h"
46 #include "cpl_error_internal.h"
47
48 #if !defined(va_copy) && defined(__va_copy)
49 #define va_copy __va_copy
50 #endif
51
52 #define TIMESTAMP_DEBUG
53 // #define MEMORY_DEBUG
54
55 CPL_CVSID("$Id: cpl_error.cpp fd224846daf82b3fbdf90f870fd7eb2020c9e23c 2021-09-24 19:35:24 +0200 Even Rouault $")
56
57 static CPLMutex *hErrorMutex = nullptr;
58 static void *pErrorHandlerUserData = nullptr;
59 static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
60 static bool gbCatchDebug = true;
61
62 constexpr int DEFAULT_LAST_ERR_MSG_SIZE =
63 #if !defined(HAVE_VSNPRINTF)
64 20000
65 #else
66 500
67 #endif
68 ;
69
70 typedef struct errHandler
71 {
72 struct errHandler *psNext;
73 void *pUserData;
74 CPLErrorHandler pfnHandler;
75 bool bCatchDebug;
76 } CPLErrorHandlerNode;
77
78 typedef struct {
79 CPLErrorNum nLastErrNo;
80 CPLErr eLastErrType;
81 CPLErrorHandlerNode *psHandlerStack;
82 int nLastErrMsgMax;
83 int nFailureIntoWarning;
84 GUInt32 nErrorCounter;
85 char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
86 // Do not add anything here. szLastErrMsg must be the last field.
87 // See CPLRealloc() below.
88 } CPLErrorContext;
89
90 constexpr CPLErrorContext sNoErrorContext =
91 {
92 0,
93 CE_None,
94 nullptr,
95 0,
96 0,
97 0,
98 ""
99 };
100
101 constexpr CPLErrorContext sWarningContext =
102 {
103 0,
104 CE_Warning,
105 nullptr,
106 0,
107 0,
108 0,
109 "A warning was emitted"
110 };
111
112 constexpr CPLErrorContext sFailureContext =
113 {
114 0,
115 CE_Warning,
116 nullptr,
117 0,
118 0,
119 0,
120 "A failure was emitted"
121 };
122
123 #define IS_PREFEFINED_ERROR_CTX(psCtxt) ( psCtx == &sNoErrorContext || \
124 psCtx == &sWarningContext || \
125 psCtxt == &sFailureContext )
126
127
128 /************************************************************************/
129 /* CPLErrorContextGetString() */
130 /************************************************************************/
131
132 // Makes clang -fsanitize=undefined happy since it doesn't like
133 // dereferencing szLastErrMsg[i>=DEFAULT_LAST_ERR_MSG_SIZE]
134
CPLErrorContextGetString(CPLErrorContext * psCtxt)135 static char* CPLErrorContextGetString(CPLErrorContext* psCtxt)
136 {
137 return psCtxt->szLastErrMsg;
138 }
139
140 /************************************************************************/
141 /* CPLGetErrorContext() */
142 /************************************************************************/
143
CPLGetErrorContext()144 static CPLErrorContext *CPLGetErrorContext()
145
146 {
147 int bError = FALSE;
148 CPLErrorContext *psCtx =
149 reinterpret_cast<CPLErrorContext *>(
150 CPLGetTLSEx( CTLS_ERRORCONTEXT, &bError ) );
151 if( bError )
152 return nullptr;
153
154 if( psCtx == nullptr )
155 {
156 psCtx = static_cast<CPLErrorContext *>(
157 VSICalloc( sizeof(CPLErrorContext), 1) );
158 if( psCtx == nullptr )
159 {
160 fprintf(stderr, "Out of memory attempting to report error.\n");
161 return nullptr;
162 }
163 psCtx->eLastErrType = CE_None;
164 psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
165 CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
166 }
167
168 return psCtx;
169 }
170
171 /************************************************************************/
172 /* CPLGetErrorHandlerUserData() */
173 /************************************************************************/
174
175 /**
176 * Fetch the user data for the error context
177 *
178 * Fetches the user data for the current error context. You can
179 * set the user data for the error context when you add your handler by
180 * issuing CPLSetErrorHandlerEx() and CPLPushErrorHandlerEx(). Note that
181 * user data is primarily intended for providing context within error handlers
182 * themselves, but they could potentially be abused in other useful ways with
183 * the usual caveat emptor understanding.
184 *
185 * @return the user data pointer for the error context
186 */
187
CPLGetErrorHandlerUserData(void)188 void* CPL_STDCALL CPLGetErrorHandlerUserData(void)
189 {
190 int bError = FALSE;
191
192 // check if there is an active error being propagated through the handlers
193 void **pActiveUserData = reinterpret_cast<void **>(
194 CPLGetTLSEx( CTLS_ERRORHANDLERACTIVEDATA, &bError ) );
195 if( bError )
196 return nullptr;
197
198 if ( pActiveUserData != nullptr)
199 {
200 return *pActiveUserData;
201 }
202
203 // get the current threadlocal or global error context user data
204 CPLErrorContext *psCtx = CPLGetErrorContext();
205 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
206 abort();
207 return reinterpret_cast<void*>(
208 psCtx->psHandlerStack ?
209 psCtx->psHandlerStack->pUserData : pErrorHandlerUserData );
210 }
211
ApplyErrorHandler(CPLErrorContext * psCtx,CPLErr eErrClass,CPLErrorNum err_no,const char * pszMessage)212 static void ApplyErrorHandler( CPLErrorContext *psCtx, CPLErr eErrClass,
213 CPLErrorNum err_no, const char *pszMessage)
214 {
215 void **pActiveUserData;
216 bool bProcessed = false;
217
218 // CTLS_ERRORHANDLERACTIVEDATA holds the active error handler userData
219
220 if( psCtx->psHandlerStack != nullptr )
221 {
222 // iterate through the threadlocal handler stack
223 if( (eErrClass != CE_Debug) || psCtx->psHandlerStack->bCatchDebug )
224 {
225 // call the error handler
226 pActiveUserData = &(psCtx->psHandlerStack->pUserData);
227 CPLSetTLS( CTLS_ERRORHANDLERACTIVEDATA, pActiveUserData, false );
228 psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMessage);
229 bProcessed = true;
230 }
231 else
232 {
233 // need to iterate to a parent handler for debug messages
234 CPLErrorHandlerNode *psNode = psCtx->psHandlerStack->psNext;
235 while( psNode != nullptr )
236 {
237 if( psNode->bCatchDebug )
238 {
239 pActiveUserData = &(psNode->pUserData);
240 CPLSetTLS( CTLS_ERRORHANDLERACTIVEDATA, pActiveUserData, false );
241 psNode->pfnHandler( eErrClass, err_no, pszMessage );
242 bProcessed = true;
243 break;
244 }
245 psNode = psNode->psNext;
246 }
247 }
248 }
249
250 if( !bProcessed )
251 {
252 // hit the global error handler
253 CPLMutexHolderD( &hErrorMutex );
254 if( (eErrClass != CE_Debug) || gbCatchDebug )
255 {
256 if( pfnErrorHandler != nullptr )
257 {
258 pActiveUserData = &pErrorHandlerUserData;
259 CPLSetTLS( CTLS_ERRORHANDLERACTIVEDATA, pActiveUserData, false );
260 pfnErrorHandler(eErrClass, err_no, pszMessage);
261 }
262 }
263 else /* if( eErrClass == CE_Debug ) */
264 {
265 // for CPLDebug messages we propagate to the default error handler
266 pActiveUserData = nullptr;
267 CPLSetTLS( CTLS_ERRORHANDLERACTIVEDATA, pActiveUserData, false );
268 CPLDefaultErrorHandler(eErrClass, err_no, pszMessage);
269 }
270 }
271 CPLSetTLS( CTLS_ERRORHANDLERACTIVEDATA, nullptr, false );
272 }
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
CPLError(CPLErr eErrClass,CPLErrorNum err_no,CPL_FORMAT_STRING (const char * fmt),...)310 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 va_start(args, fmt);
317 CPLErrorV( eErrClass, err_no, fmt, args );
318 va_end(args);
319 }
320
321 /************************************************************************/
322 /* CPLErrorV() */
323 /************************************************************************/
324
325 /** Same as CPLError() but with a va_list */
CPLErrorV(CPLErr eErrClass,CPLErrorNum err_no,const char * fmt,va_list args)326 void CPLErrorV( CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
327 va_list args )
328 {
329 CPLErrorContext *psCtx = CPLGetErrorContext();
330 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
331 {
332 int bMemoryError = FALSE;
333 if( eErrClass == CE_Warning )
334 {
335 CPLSetTLSWithFreeFuncEx(
336 CTLS_ERRORCONTEXT,
337 reinterpret_cast<void*>(
338 const_cast<CPLErrorContext *>( &sWarningContext ) ),
339 nullptr, &bMemoryError );
340 }
341 else if( eErrClass == CE_Failure )
342 {
343 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 char szShortMessage[80] = {};
353 CPLvsnprintf( szShortMessage, sizeof(szShortMessage), fmt, args );
354
355 CPLMutexHolderD( &hErrorMutex );
356 if( pfnErrorHandler != nullptr )
357 pfnErrorHandler(eErrClass, err_no, szShortMessage);
358 return;
359 }
360
361 if( psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure )
362 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 va_copy( wrk_args, args );
373 #else
374 wrk_args = args;
375 #endif
376
377 /* -------------------------------------------------------------------- */
378 /* If CPL_ACCUM_ERROR_MSG=ON accumulate the error messages, */
379 /* rather than just replacing the last error message. */
380 /* -------------------------------------------------------------------- */
381 int nPreviousSize = 0;
382 if( psCtx->psHandlerStack != nullptr &&
383 EQUAL(CPLGetConfigOption( "CPL_ACCUM_ERROR_MSG", "" ), "ON"))
384 {
385 nPreviousSize = static_cast<int>(strlen(psCtx->szLastErrMsg));
386 if( nPreviousSize )
387 {
388 if( nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax )
389 {
390 psCtx->nLastErrMsgMax *= 3;
391 psCtx = static_cast<CPLErrorContext *> (
392 CPLRealloc(psCtx,
393 sizeof(CPLErrorContext)
394 - DEFAULT_LAST_ERR_MSG_SIZE
395 + psCtx->nLastErrMsgMax + 1));
396 CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
397 }
398 char* pszLastErrMsg = CPLErrorContextGetString(psCtx);
399 pszLastErrMsg[nPreviousSize] = '\n';
400 pszLastErrMsg[nPreviousSize+1] = '\0';
401 nPreviousSize++;
402 }
403 }
404
405 int nPR = 0;
406 while( ((nPR = CPLvsnprintf(
407 psCtx->szLastErrMsg+nPreviousSize,
408 psCtx->nLastErrMsgMax-nPreviousSize, fmt, wrk_args )) == -1
409 || nPR >= psCtx->nLastErrMsgMax-nPreviousSize-1)
410 && psCtx->nLastErrMsgMax < 1000000 )
411 {
412 #ifdef va_copy
413 va_end( wrk_args );
414 va_copy( wrk_args, args );
415 #else
416 wrk_args = args;
417 #endif
418 psCtx->nLastErrMsgMax *= 3;
419 psCtx = static_cast<CPLErrorContext *> (
420 CPLRealloc(psCtx,
421 sizeof(CPLErrorContext)
422 - DEFAULT_LAST_ERR_MSG_SIZE
423 + psCtx->nLastErrMsgMax + 1));
424 CPLSetTLS( CTLS_ERRORCONTEXT, psCtx, TRUE );
425 }
426
427 va_end( wrk_args );
428 }
429 #else
430 // !HAVE_VSNPRINTF
431 CPLvsnprintf( psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
432 #endif
433
434 /* -------------------------------------------------------------------- */
435 /* Obfuscate any password in error message */
436 /* -------------------------------------------------------------------- */
437 char* pszPassword = strstr(psCtx->szLastErrMsg, "password=");
438 if( pszPassword != nullptr )
439 {
440 char* pszIter = pszPassword + strlen("password=");
441 while( *pszIter != ' ' && *pszIter != '\0' )
442 {
443 *pszIter = 'X';
444 pszIter++;
445 }
446 }
447
448 /* -------------------------------------------------------------------- */
449 /* If the user provided an handling function, then */
450 /* call it, otherwise print the error to stderr and return. */
451 /* -------------------------------------------------------------------- */
452 psCtx->nLastErrNo = err_no;
453 psCtx->eLastErrType = eErrClass;
454 if( psCtx->nErrorCounter == ~(0U) )
455 psCtx->nErrorCounter = 0;
456 else
457 psCtx->nErrorCounter ++;
458
459 if( CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr )
460 CPLDebug( "CPLError", "%s", psCtx->szLastErrMsg );
461
462 /* -------------------------------------------------------------------- */
463 /* Invoke the current error handler. */
464 /* -------------------------------------------------------------------- */
465 ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
466
467 if( eErrClass == CE_Fatal )
468 abort();
469 }
470
471 /************************************************************************/
472 /* CPLEmergencyError() */
473 /************************************************************************/
474
475 /**
476 * Fatal error when things are bad.
477 *
478 * This function should be called in an emergency situation where
479 * it is unlikely that a regular error report would work. This would
480 * include in the case of heap exhaustion for even small allocations,
481 * or any failure in the process of reporting an error (such as TLS
482 * allocations).
483 *
484 * This function should never return. After the error message has been
485 * reported as best possible, the application will abort() similarly to how
486 * CPLError() aborts on CE_Fatal class errors.
487 *
488 * @param pszMessage the error message to report.
489 */
490
CPLEmergencyError(const char * pszMessage)491 void CPLEmergencyError( const char *pszMessage )
492 {
493 static bool bInEmergencyError = false;
494
495 // If we are already in emergency error then one of the
496 // following failed, so avoid them the second time through.
497 if( !bInEmergencyError )
498 {
499 bInEmergencyError = true;
500 CPLErrorContext *psCtx =
501 static_cast<CPLErrorContext *>(CPLGetTLS( CTLS_ERRORCONTEXT ));
502
503 ApplyErrorHandler(psCtx, CE_Fatal, CPLE_AppDefined, pszMessage);
504 }
505
506 // Ultimate fallback.
507 fprintf( stderr, "FATAL: %s\n", pszMessage );
508
509 abort();
510 }
511
512 /************************************************************************/
513 /* CPLGetProcessMemorySize() */
514 /************************************************************************/
515
516 #ifdef MEMORY_DEBUG
517
518 #ifdef __linux
CPLGetProcessMemorySize()519 static int CPLGetProcessMemorySize()
520 {
521 FILE* fp = fopen("/proc/self/status", "r");
522 if( fp == nullptr )
523 return -1;
524 int nRet = -1;
525 char szLine[128] = {};
526 while( fgets(szLine, sizeof(szLine), fp) != nullptr )
527 {
528 if( STARTS_WITH(szLine, "VmSize:") )
529 {
530 const char* pszPtr = szLine;
531 while( !(*pszPtr == '\0' || (*pszPtr >= '0' && *pszPtr <= '9')) )
532 pszPtr++;
533 nRet = atoi(pszPtr);
534 break;
535 }
536 }
537 fclose(fp);
538 return nRet;
539 }
540 #else
541 #error CPLGetProcessMemorySize() unimplemented for this OS
542 #endif
543
544 #endif // def MEMORY_DEBUG
545
546
547
548 /************************************************************************/
549 /* CPLGettimeofday() */
550 /************************************************************************/
551
552 #if defined(_WIN32) && !defined(__CYGWIN__)
553 # include <sys/timeb.h>
554
555 namespace {
556 struct CPLTimeVal
557 {
558 time_t tv_sec; /* seconds */
559 long tv_usec; /* and microseconds */
560 };
561 }
562
CPLGettimeofday(struct CPLTimeVal * tp,void *)563 static int CPLGettimeofday(struct CPLTimeVal* tp, void* /* timezonep*/ )
564 {
565 struct _timeb theTime;
566
567 _ftime(&theTime);
568 tp->tv_sec = static_cast<time_t>(theTime.time);
569 tp->tv_usec = theTime.millitm * 1000;
570 return 0;
571 }
572 #else
573 # include <sys/time.h> /* for gettimeofday() */
574 # define CPLTimeVal timeval
575 # define CPLGettimeofday(t,u) gettimeofday(t,u)
576 #endif
577
578
579 /************************************************************************/
580 /* CPLDebug() */
581 /************************************************************************/
582
583 /**
584 * Display a debugging message.
585 *
586 * The category argument is used in conjunction with the CPL_DEBUG
587 * environment variable to establish if the message should be displayed.
588 * If the CPL_DEBUG environment variable is not set, no debug messages
589 * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
590 * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
591 * debug messages are shown. Otherwise only messages whose category appears
592 * somewhere within the CPL_DEBUG value are displayed (as determined by
593 * strstr()).
594 *
595 * Categories are usually an identifier for the subsystem producing the
596 * error. For instance "GDAL" might be used for the GDAL core, and "TIFF"
597 * for messages from the TIFF translator.
598 *
599 * @param pszCategory name of the debugging message category.
600 * @param pszFormat printf() style format string for message to display.
601 * Remaining arguments are assumed to be for format.
602 */
603
604 #ifdef WITHOUT_CPLDEBUG
605 // Do not include CPLDebug. Only available in custom builds.
606 #else
CPLDebug(const char * pszCategory,CPL_FORMAT_STRING (const char * pszFormat),...)607 void CPLDebug( const char * pszCategory,
608 CPL_FORMAT_STRING(const char * pszFormat), ... )
609
610 {
611 CPLErrorContext *psCtx = CPLGetErrorContext();
612 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
613 return;
614 const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
615
616 /* -------------------------------------------------------------------- */
617 /* Does this message pass our current criteria? */
618 /* -------------------------------------------------------------------- */
619 if( pszDebug == nullptr )
620 return;
621
622 if( !EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, "") )
623 {
624 const size_t nLen = strlen(pszCategory);
625
626 size_t i = 0;
627 for( i = 0; pszDebug[i] != '\0'; i++ )
628 {
629 if( EQUALN(pszCategory, pszDebug+i, nLen) )
630 break;
631 }
632
633 if( pszDebug[i] == '\0' )
634 return;
635 }
636
637 /* -------------------------------------------------------------------- */
638 /* Allocate a block for the error. */
639 /* -------------------------------------------------------------------- */
640 const int ERROR_MAX = 25000;
641 char *pszMessage = static_cast<char *>( VSIMalloc( ERROR_MAX ) );
642 if( pszMessage == nullptr )
643 return;
644
645 /* -------------------------------------------------------------------- */
646 /* Dal -- always log a timestamp as the first part of the line */
647 /* to ensure one is looking at what one should be looking at! */
648 /* -------------------------------------------------------------------- */
649
650 pszMessage[0] = '\0';
651 #ifdef TIMESTAMP_DEBUG
652 if( CPLGetConfigOption( "CPL_TIMESTAMP", nullptr ) != nullptr )
653 {
654 static struct CPLTimeVal tvStart;
655 static const auto unused = CPLGettimeofday(&tvStart, nullptr);
656 CPL_IGNORE_RET_VAL(unused);
657 struct CPLTimeVal tv;
658 CPLGettimeofday(&tv, nullptr);
659 strcpy( pszMessage, "[" );
660 strcat( pszMessage, VSICTime( static_cast<unsigned long>(tv.tv_sec) ) );
661
662 // On windows anyway, ctime puts a \n at the end, but I'm not
663 // convinced this is standard behavior, so we'll get rid of it
664 // carefully
665
666 if( pszMessage[strlen(pszMessage) -1 ] == '\n' )
667 {
668 pszMessage[strlen(pszMessage) - 1] = 0; // blow it out
669 }
670 CPLsnprintf(pszMessage+strlen(pszMessage),
671 ERROR_MAX - strlen(pszMessage),
672 "].%04d, %03.04f: ",
673 static_cast<int>(tv.tv_usec / 100),
674 tv.tv_sec + tv.tv_usec * 1e-6 -
675 (tvStart.tv_sec + tvStart.tv_usec * 1e-6));
676 }
677 #endif
678
679 /* -------------------------------------------------------------------- */
680 /* Add the process memory size. */
681 /* -------------------------------------------------------------------- */
682 #ifdef MEMORY_DEBUG
683 char szVmSize[32] = {};
684 CPLsprintf( szVmSize, "[VmSize: %d] ", CPLGetProcessMemorySize());
685 strcat( pszMessage, szVmSize );
686 #endif
687
688 /* -------------------------------------------------------------------- */
689 /* Add the category. */
690 /* -------------------------------------------------------------------- */
691 strcat( pszMessage, pszCategory );
692 strcat( pszMessage, ": " );
693
694 /* -------------------------------------------------------------------- */
695 /* Format the application provided portion of the debug message. */
696 /* -------------------------------------------------------------------- */
697 va_list args;
698 va_start(args, pszFormat);
699
700 CPLvsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage),
701 pszFormat, args);
702
703 va_end(args);
704
705 /* -------------------------------------------------------------------- */
706 /* Obfuscate any password in error message */
707 /* -------------------------------------------------------------------- */
708
709 char* pszPassword = strstr(pszMessage, "password=");
710 if( pszPassword != nullptr )
711 {
712 char* pszIter = pszPassword + strlen("password=");
713 while( *pszIter != ' ' && *pszIter != '\0' )
714 {
715 *pszIter = 'X';
716 pszIter++;
717 }
718 }
719
720 /* -------------------------------------------------------------------- */
721 /* Invoke the current error handler. */
722 /* -------------------------------------------------------------------- */
723 ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
724
725 VSIFree( pszMessage );
726 }
727 #endif // !WITHOUT_CPLDEBUG
728
729 /**********************************************************************
730 * CPLErrorReset()
731 **********************************************************************/
732
733 /**
734 * Erase any traces of previous errors.
735 *
736 * This is normally used to ensure that an error which has been recovered
737 * from does not appear to be still in play with high level functions.
738 */
739
CPLErrorReset()740 void CPL_STDCALL CPLErrorReset()
741 {
742 CPLErrorContext *psCtx = CPLGetErrorContext();
743 if( psCtx == nullptr )
744 return;
745 if( IS_PREFEFINED_ERROR_CTX(psCtx) )
746 {
747 int bMemoryError = FALSE;
748 CPLSetTLSWithFreeFuncEx(
749 CTLS_ERRORCONTEXT,
750 reinterpret_cast<void*>(
751 const_cast<CPLErrorContext *>( &sNoErrorContext ) ),
752 nullptr, &bMemoryError );
753 return;
754 }
755
756 psCtx->nLastErrNo = CPLE_None;
757 psCtx->szLastErrMsg[0] = '\0';
758 psCtx->eLastErrType = CE_None;
759 psCtx->nErrorCounter = 0;
760 }
761
762 /**********************************************************************
763 * CPLErrorSetState()
764 **********************************************************************/
765
766 /**
767 * Restore an error state, without emitting an error.
768 *
769 * Can be useful if a routine might call CPLErrorReset() and one wants to
770 * preserve the previous error state.
771 *
772 * @since GDAL 2.0
773 */
774
CPLErrorSetState(CPLErr eErrClass,CPLErrorNum err_no,const char * pszMsg)775 void CPL_DLL CPLErrorSetState( CPLErr eErrClass, CPLErrorNum err_no,
776 const char* pszMsg )
777 {
778 CPLErrorContext *psCtx = CPLGetErrorContext();
779 if( psCtx == nullptr )
780 return;
781 if( IS_PREFEFINED_ERROR_CTX(psCtx) )
782 {
783 int bMemoryError = FALSE;
784 if( eErrClass == CE_None )
785 CPLSetTLSWithFreeFuncEx(
786 CTLS_ERRORCONTEXT,
787 reinterpret_cast<void*>(
788 const_cast<CPLErrorContext *>( &sNoErrorContext ) ),
789 nullptr, &bMemoryError );
790 else if( eErrClass == CE_Warning )
791 CPLSetTLSWithFreeFuncEx(
792 CTLS_ERRORCONTEXT,
793 reinterpret_cast<void*>(
794 const_cast<CPLErrorContext *>( &sWarningContext ) ),
795 nullptr, &bMemoryError );
796 else if( eErrClass == CE_Failure )
797 CPLSetTLSWithFreeFuncEx(
798 CTLS_ERRORCONTEXT,
799 reinterpret_cast<void*>(
800 const_cast<CPLErrorContext *>( &sFailureContext ) ),
801 nullptr, &bMemoryError );
802 return;
803 }
804
805 psCtx->nLastErrNo = err_no;
806 const size_t size = std::min(
807 static_cast<size_t>(psCtx->nLastErrMsgMax-1), strlen(pszMsg) );
808 char* pszLastErrMsg = CPLErrorContextGetString(psCtx);
809 memcpy( pszLastErrMsg, pszMsg, size );
810 pszLastErrMsg[size] = '\0';
811 psCtx->eLastErrType = eErrClass;
812 }
813
814 /**********************************************************************
815 * CPLGetLastErrorNo()
816 **********************************************************************/
817
818 /**
819 * Fetch the last error number.
820 *
821 * Fetches the last error number posted with CPLError(), that hasn't
822 * been cleared by CPLErrorReset(). This is the error number, not the error
823 * class.
824 *
825 * @return the error number of the last error to occur, or CPLE_None (0)
826 * if there are no posted errors.
827 */
828
CPLGetLastErrorNo()829 CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
830 {
831 CPLErrorContext *psCtx = CPLGetErrorContext();
832 if( psCtx == nullptr )
833 return 0;
834
835 return psCtx->nLastErrNo;
836 }
837
838 /**********************************************************************
839 * CPLGetLastErrorType()
840 **********************************************************************/
841
842 /**
843 * Fetch the last error type.
844 *
845 * Fetches the last error type posted with CPLError(), that hasn't
846 * been cleared by CPLErrorReset(). This is the error class, not the error
847 * number.
848 *
849 * @return the error type of the last error to occur, or CE_None (0)
850 * if there are no posted errors.
851 */
852
CPLGetLastErrorType()853 CPLErr CPL_STDCALL CPLGetLastErrorType()
854 {
855 CPLErrorContext *psCtx = CPLGetErrorContext();
856 if( psCtx == nullptr )
857 return CE_None;
858
859 return psCtx->eLastErrType;
860 }
861
862 /**********************************************************************
863 * CPLGetLastErrorMsg()
864 **********************************************************************/
865
866 /**
867 * Get the last error message.
868 *
869 * Fetches the last error message posted with CPLError(), that hasn't
870 * been cleared by CPLErrorReset(). The returned pointer is to an internal
871 * string that should not be altered or freed.
872 *
873 * @return the last error message, or NULL if there is no posted error
874 * message.
875 */
876
CPLGetLastErrorMsg()877 const char* CPL_STDCALL CPLGetLastErrorMsg()
878 {
879 CPLErrorContext *psCtx = CPLGetErrorContext();
880 if( psCtx == nullptr )
881 return "";
882
883 return psCtx->szLastErrMsg;
884 }
885
886 /**********************************************************************
887 * CPLGetErrorCounter()
888 **********************************************************************/
889
890 /**
891 * Get the error counter
892 *
893 * Fetches the number of errors emitted in the current error context,
894 * since the last call to CPLErrorReset()
895 *
896 * @return the error counter.
897 * @since GDAL 2.3
898 */
899
CPLGetErrorCounter()900 GUInt32 CPL_STDCALL CPLGetErrorCounter()
901 {
902 CPLErrorContext *psCtx = CPLGetErrorContext();
903 if( psCtx == nullptr )
904 return 0;
905
906 return psCtx->nErrorCounter;
907 }
908
909 /************************************************************************/
910 /* CPLDefaultErrorHandler() */
911 /************************************************************************/
912
913 static FILE *fpLog = stderr;
914 static bool bLogInit = false;
915
CPLfopenUTF8(const char * pszFilename,const char * pszAccess)916 static FILE* CPLfopenUTF8(const char* pszFilename, const char* pszAccess)
917 {
918 FILE* f;
919 #ifdef _WIN32
920 wchar_t *pwszFilename =
921 CPLRecodeToWChar( pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2 );
922 wchar_t *pwszAccess =
923 CPLRecodeToWChar( pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2 );
924 f = _wfopen(pwszFilename, pwszAccess);
925 VSIFree(pwszFilename);
926 VSIFree(pwszAccess);
927 #else
928 f = fopen( pszFilename, pszAccess );
929 #endif
930 return f;
931 }
932
933 /** Default error handler. */
CPLDefaultErrorHandler(CPLErr eErrClass,CPLErrorNum nError,const char * pszErrorMsg)934 void CPL_STDCALL CPLDefaultErrorHandler( CPLErr eErrClass, CPLErrorNum nError,
935 const char * pszErrorMsg )
936
937 {
938 static int nCount = 0;
939 static int nMaxErrors = -1;
940
941 if( eErrClass != CE_Debug )
942 {
943 if( nMaxErrors == -1 )
944 {
945 nMaxErrors =
946 atoi(CPLGetConfigOption( "CPL_MAX_ERROR_REPORTS", "1000" ));
947 }
948
949 nCount++;
950 if( nCount > nMaxErrors && nMaxErrors > 0 )
951 return;
952 }
953
954 if( !bLogInit )
955 {
956 bLogInit = true;
957
958 fpLog = stderr;
959 const char* pszLog = CPLGetConfigOption( "CPL_LOG", nullptr );
960 if( pszLog != nullptr )
961 {
962 const bool bAppend = CPLGetConfigOption( "CPL_LOG_APPEND", nullptr ) != nullptr;
963 const char* pszAccess = bAppend ? "at" : "wt";
964 fpLog = CPLfopenUTF8( pszLog, pszAccess );
965 if( fpLog == nullptr )
966 fpLog = stderr;
967 }
968 }
969
970 if( eErrClass == CE_Debug )
971 fprintf( fpLog, "%s\n", pszErrorMsg );
972 else if( eErrClass == CE_Warning )
973 fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
974 else
975 fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
976
977 if( eErrClass != CE_Debug
978 && nMaxErrors > 0
979 && nCount == nMaxErrors )
980 {
981 fprintf( fpLog,
982 "More than %d errors or warnings have been reported. "
983 "No more will be reported from now.\n",
984 nMaxErrors );
985 }
986
987 fflush( fpLog );
988 }
989
990 /************************************************************************/
991 /* CPLQuietErrorHandler() */
992 /************************************************************************/
993
994 /** Error handler that does not do anything, except for debug messages. */
CPLQuietErrorHandler(CPLErr eErrClass,CPLErrorNum nError,const char * pszErrorMsg)995 void CPL_STDCALL CPLQuietErrorHandler( CPLErr eErrClass , CPLErrorNum nError,
996 const char * pszErrorMsg )
997
998 {
999 if( eErrClass == CE_Debug )
1000 CPLDefaultErrorHandler( eErrClass, nError, pszErrorMsg );
1001 }
1002
1003 /************************************************************************/
1004 /* CPLLoggingErrorHandler() */
1005 /************************************************************************/
1006
1007 /** Error handler that logs into the file defined by the CPL_LOG configuration
1008 * option, or stderr otherwise.
1009 */
CPLLoggingErrorHandler(CPLErr eErrClass,CPLErrorNum nError,const char * pszErrorMsg)1010 void CPL_STDCALL CPLLoggingErrorHandler( CPLErr eErrClass, CPLErrorNum nError,
1011 const char * pszErrorMsg )
1012
1013 {
1014 if( !bLogInit )
1015 {
1016 bLogInit = true;
1017
1018 CPLSetConfigOption( "CPL_TIMESTAMP", "ON" );
1019
1020 const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr );
1021
1022 fpLog = stderr;
1023 if( cpl_log != nullptr && EQUAL(cpl_log, "OFF") )
1024 {
1025 fpLog = nullptr;
1026 }
1027 else if( cpl_log != nullptr )
1028 {
1029 size_t nPathLen = strlen(cpl_log) + 20;
1030 char* pszPath = static_cast<char *>(CPLMalloc(nPathLen));
1031 strcpy(pszPath, cpl_log);
1032
1033 int i = 0;
1034 while( (fpLog = CPLfopenUTF8( pszPath, "rt" )) != nullptr )
1035 {
1036 fclose( fpLog );
1037
1038 // Generate sequenced log file names, inserting # before ext.
1039 if( strrchr(cpl_log, '.') == nullptr )
1040 {
1041 snprintf( pszPath, nPathLen, "%s_%d%s", cpl_log, i++,
1042 ".log" );
1043 }
1044 else
1045 {
1046 size_t pos = 0;
1047 char *cpl_log_base = CPLStrdup(cpl_log);
1048 pos = strcspn(cpl_log_base, ".");
1049 if( pos > 0 )
1050 {
1051 cpl_log_base[pos] = '\0';
1052 }
1053 snprintf( pszPath, nPathLen, "%s_%d%s", cpl_log_base,
1054 i++, ".log" );
1055 CPLFree(cpl_log_base);
1056 }
1057 }
1058
1059 fpLog = CPLfopenUTF8( pszPath, "wt" );
1060 CPLFree(pszPath);
1061 }
1062 }
1063
1064 if( fpLog == nullptr )
1065 return;
1066
1067 if( eErrClass == CE_Debug )
1068 fprintf( fpLog, "%s\n", pszErrorMsg );
1069 else if( eErrClass == CE_Warning )
1070 fprintf( fpLog, "Warning %d: %s\n", nError, pszErrorMsg );
1071 else
1072 fprintf( fpLog, "ERROR %d: %s\n", nError, pszErrorMsg );
1073
1074 fflush( fpLog );
1075 }
1076
1077 /**********************************************************************
1078 * CPLTurnFailureIntoWarning() *
1079 **********************************************************************/
1080
1081 /** Whether failures should be turned into warnings.
1082 */
CPLTurnFailureIntoWarning(int bOn)1083 void CPLTurnFailureIntoWarning( int bOn )
1084 {
1085 CPLErrorContext *psCtx = CPLGetErrorContext();
1086 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
1087 {
1088 fprintf(stderr, "CPLTurnFailureIntoWarning() failed.\n");
1089 return;
1090 }
1091 psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
1092 if( psCtx->nFailureIntoWarning < 0 )
1093 {
1094 CPLDebug( "CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / "
1095 "CPLTurnFailureIntoWarning(FALSE)" );
1096 }
1097 }
1098
1099 /**********************************************************************
1100 * CPLSetErrorHandlerEx() *
1101 **********************************************************************/
1102
1103 /**
1104 * Install custom error handle with user's data. This method is
1105 * essentially CPLSetErrorHandler with an added pointer to pUserData.
1106 * The pUserData is not returned in the CPLErrorHandler, however, and
1107 * must be fetched via CPLGetErrorHandlerUserData.
1108 *
1109 * @param pfnErrorHandlerNew new error handler function.
1110 * @param pUserData User data to carry along with the error context.
1111 * @return returns the previously installed error handler.
1112 */
1113
1114 CPLErrorHandler CPL_STDCALL
CPLSetErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,void * pUserData)1115 CPLSetErrorHandlerEx( CPLErrorHandler pfnErrorHandlerNew, void* pUserData )
1116 {
1117 CPLErrorContext *psCtx = CPLGetErrorContext();
1118 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
1119 {
1120 fprintf(stderr, "CPLSetErrorHandlerEx() failed.\n");
1121 return nullptr;
1122 }
1123
1124 if( psCtx->psHandlerStack != nullptr )
1125 {
1126 CPLDebug( "CPL",
1127 "CPLSetErrorHandler() called with an error handler on "
1128 "the local stack. New error handler will not be used "
1129 "immediately." );
1130 }
1131
1132 CPLErrorHandler pfnOldHandler = nullptr;
1133 {
1134 CPLMutexHolderD( &hErrorMutex );
1135
1136 pfnOldHandler = pfnErrorHandler;
1137
1138 pfnErrorHandler = pfnErrorHandlerNew;
1139
1140 pErrorHandlerUserData = pUserData;
1141 }
1142
1143 return pfnOldHandler;
1144 }
1145
1146 /**********************************************************************
1147 * CPLSetErrorHandler() *
1148 **********************************************************************/
1149
1150 /**
1151 * Install custom error handler.
1152 *
1153 * Allow the library's user to specify an error handler function.
1154 * A valid error handler is a C function with the following prototype:
1155 *
1156 * <pre>
1157 * void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
1158 * </pre>
1159 *
1160 * Pass NULL to come back to the default behavior. The default behavior
1161 * (CPLDefaultErrorHandler()) is to write the message to stderr.
1162 *
1163 * The msg will be a partially formatted error message not containing the
1164 * "ERROR %d:" portion emitted by the default handler. Message formatting
1165 * is handled by CPLError() before calling the handler. If the error
1166 * handler function is passed a CE_Fatal class error and returns, then
1167 * CPLError() will call abort(). Applications wanting to interrupt this
1168 * fatal behavior will have to use longjmp(), or a C++ exception to
1169 * indirectly exit the function.
1170 *
1171 * Another standard error handler is CPLQuietErrorHandler() which doesn't
1172 * make any attempt to report the passed error or warning messages but
1173 * will process debug messages via CPLDefaultErrorHandler.
1174 *
1175 * Note that error handlers set with CPLSetErrorHandler() apply to all
1176 * threads in an application, while error handlers set with CPLPushErrorHandler
1177 * are thread-local. However, any error handlers pushed with
1178 * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
1179 * precedence over the global error handlers set with CPLSetErrorHandler().
1180 * Generally speaking CPLSetErrorHandler() would be used to set a desired
1181 * global error handler, while CPLPushErrorHandler() would be used to install
1182 * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
1183 * error reporting in a limited segment of code.
1184 *
1185 * @param pfnErrorHandlerNew new error handler function.
1186 * @return returns the previously installed error handler.
1187 */
1188 CPLErrorHandler CPL_STDCALL
CPLSetErrorHandler(CPLErrorHandler pfnErrorHandlerNew)1189 CPLSetErrorHandler( CPLErrorHandler pfnErrorHandlerNew )
1190 {
1191 return CPLSetErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1192 }
1193
1194 /************************************************************************/
1195 /* CPLPushErrorHandler() */
1196 /************************************************************************/
1197
1198 /**
1199 * Push a new CPLError handler.
1200 *
1201 * This pushes a new error handler on the thread-local error handler
1202 * stack. This handler will be used until removed with CPLPopErrorHandler().
1203 *
1204 * The CPLSetErrorHandler() docs have further information on how
1205 * CPLError handlers work.
1206 *
1207 * @param pfnErrorHandlerNew new error handler function.
1208 */
1209
CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)1210 void CPL_STDCALL CPLPushErrorHandler( CPLErrorHandler pfnErrorHandlerNew )
1211
1212 {
1213 CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1214 }
1215
1216 /************************************************************************/
1217 /* CPLPushErrorHandlerEx() */
1218 /************************************************************************/
1219
1220 /**
1221 * Push a new CPLError handler with user data on the error context.
1222 *
1223 * This pushes a new error handler on the thread-local error handler
1224 * stack. This handler will be used until removed with CPLPopErrorHandler().
1225 * Obtain the user data back by using CPLGetErrorContext().
1226 *
1227 * The CPLSetErrorHandler() docs have further information on how
1228 * CPLError handlers work.
1229 *
1230 * @param pfnErrorHandlerNew new error handler function.
1231 * @param pUserData User data to put on the error context.
1232 */
CPLPushErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,void * pUserData)1233 void CPL_STDCALL CPLPushErrorHandlerEx( CPLErrorHandler pfnErrorHandlerNew,
1234 void* pUserData )
1235
1236 {
1237 CPLErrorContext *psCtx = CPLGetErrorContext();
1238
1239 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
1240 {
1241 fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
1242 return;
1243 }
1244
1245 CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
1246 CPLMalloc( sizeof(CPLErrorHandlerNode) ) );
1247 psNode->psNext = psCtx->psHandlerStack;
1248 psNode->pfnHandler = pfnErrorHandlerNew;
1249 psNode->pUserData = pUserData;
1250 psNode->bCatchDebug = true;
1251 psCtx->psHandlerStack = psNode;
1252 }
1253
1254 /************************************************************************/
1255 /* CPLPopErrorHandler() */
1256 /************************************************************************/
1257
1258 /**
1259 * Pop error handler off stack.
1260 *
1261 * Discards the current error handler on the error handler stack, and restores
1262 * the one in use before the last CPLPushErrorHandler() call. This method
1263 * has no effect if there are no error handlers on the current threads error
1264 * handler stack.
1265 */
1266
CPLPopErrorHandler()1267 void CPL_STDCALL CPLPopErrorHandler()
1268
1269 {
1270 CPLErrorContext *psCtx = CPLGetErrorContext();
1271
1272 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
1273 {
1274 fprintf(stderr, "CPLPopErrorHandler() failed.\n");
1275 return;
1276 }
1277
1278 if( psCtx->psHandlerStack != nullptr )
1279 {
1280 CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
1281
1282 psCtx->psHandlerStack = psNode->psNext;
1283 VSIFree( psNode );
1284 }
1285 }
1286
1287 /************************************************************************/
1288 /* CPLSetCurrentErrorHandlerCatchDebug() */
1289 /************************************************************************/
1290
1291 /**
1292 * Set if the current error handler should intercept debug messages, or if
1293 * they should be processed by the previous handler.
1294 *
1295 * By default when installing a custom error handler, this one intercepts
1296 * debug messages. In some cases, this might not be desirable and the user
1297 * would prefer that the previous installed handler (or the default one if no
1298 * previous installed handler exists in the stack) deal with it. In which
1299 * case, this function should be called with bCatchDebug = FALSE.
1300 *
1301 * @param bCatchDebug FALSE if the current error handler should not intercept
1302 * debug messages
1303 * @since GDAL 2.1
1304 */
1305
CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)1306 void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug( int bCatchDebug )
1307 {
1308 CPLErrorContext *psCtx = CPLGetErrorContext();
1309
1310 if( psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx) )
1311 {
1312 fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
1313 return;
1314 }
1315
1316 if( psCtx->psHandlerStack != nullptr )
1317 psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
1318 else
1319 gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
1320 }
1321
1322 /************************************************************************/
1323 /* _CPLAssert() */
1324 /* */
1325 /* This function is called only when an assertion fails. */
1326 /************************************************************************/
1327
1328 /**
1329 * Report failure of a logical assertion.
1330 *
1331 * Applications would normally use the CPLAssert() macro which expands
1332 * into code calling _CPLAssert() only if the condition fails. _CPLAssert()
1333 * will generate a CE_Fatal error call to CPLError(), indicating the file
1334 * name, and line number of the failed assertion, as well as containing
1335 * the assertion itself.
1336 *
1337 * There is no reason for application code to call _CPLAssert() directly.
1338 */
1339
_CPLAssert(const char * pszExpression,const char * pszFile,int iLine)1340 void CPL_STDCALL _CPLAssert( const char * pszExpression, const char * pszFile,
1341 int iLine )
1342
1343 {
1344 CPLError( CE_Fatal, CPLE_AssertionFailed,
1345 "Assertion `%s' failed "
1346 "in file `%s', line %d",
1347 pszExpression, pszFile, iLine );
1348
1349 // Just to please compiler so it is aware the function does not return.
1350 abort();
1351 }
1352
1353 /************************************************************************/
1354 /* CPLCleanupErrorMutex() */
1355 /************************************************************************/
1356
CPLCleanupErrorMutex()1357 void CPLCleanupErrorMutex()
1358 {
1359 if( hErrorMutex != nullptr )
1360 {
1361 CPLDestroyMutex(hErrorMutex);
1362 hErrorMutex = nullptr;
1363 }
1364 if( fpLog != nullptr && fpLog != stderr )
1365 {
1366 fclose(fpLog);
1367 fpLog = nullptr;
1368 bLogInit = false;
1369 }
1370 }
1371
CPLIsDefaultErrorHandlerAndCatchDebug()1372 bool CPLIsDefaultErrorHandlerAndCatchDebug()
1373 {
1374 CPLErrorContext *psCtx = CPLGetErrorContext();
1375 return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
1376 gbCatchDebug &&
1377 pfnErrorHandler == CPLDefaultErrorHandler;
1378 }
1379
1380 /************************************************************************/
1381 /* CPLErrorHandlerAccumulator() */
1382 /************************************************************************/
1383
1384 static
CPLErrorHandlerAccumulator(CPLErr eErr,CPLErrorNum no,const char * msg)1385 void CPL_STDCALL CPLErrorHandlerAccumulator( CPLErr eErr, CPLErrorNum no,
1386 const char* msg )
1387 {
1388 std::vector<CPLErrorHandlerAccumulatorStruct>* paoErrors =
1389 static_cast<std::vector<CPLErrorHandlerAccumulatorStruct> *>(
1390 CPLGetErrorHandlerUserData());
1391 paoErrors->push_back(CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
1392 }
1393
1394
CPLInstallErrorHandlerAccumulator(std::vector<CPLErrorHandlerAccumulatorStruct> & aoErrors)1395 void CPLInstallErrorHandlerAccumulator(std::vector<CPLErrorHandlerAccumulatorStruct>& aoErrors)
1396 {
1397 CPLPushErrorHandlerEx( CPLErrorHandlerAccumulator, &aoErrors );
1398 }
1399
CPLUninstallErrorHandlerAccumulator()1400 void CPLUninstallErrorHandlerAccumulator()
1401 {
1402 CPLPopErrorHandler();
1403 }
1404