Coverage Report

Created: 2025-06-13 06:29

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