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