Coverage Report

Created: 2026-04-01 06:20

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