Coverage Report

Created: 2025-11-16 06:25

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
53.7k
    (psCtx == &sNoErrorContext || psCtx == &sWarningContext ||                 \
86
53.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
236
{
97
236
    return psCtxt->szLastErrMsg;
98
236
}
99
100
/************************************************************************/
101
/*                         CPLGetErrorContext()                         */
102
/************************************************************************/
103
104
static CPLErrorContext *CPLGetErrorContext()
105
106
52.4k
{
107
52.4k
    int bError = FALSE;
108
52.4k
    CPLErrorContext *psCtx = reinterpret_cast<CPLErrorContext *>(
109
52.4k
        CPLGetTLSEx(CTLS_ERRORCONTEXT, &bError));
110
52.4k
    if (bError)
111
0
        return nullptr;
112
113
52.4k
    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
52.4k
    return psCtx;
128
52.4k
}
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
24.6k
{
207
24.6k
    bool bProcessed = false;
208
209
24.6k
    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
24.6k
    if (!bProcessed)
256
24.6k
    {
257
        // hit the global error handler
258
24.6k
        CPLMutexHolderD(&hErrorMutex);
259
24.6k
        if ((eErrClass != CE_Debug) || gbCatchDebug)
260
24.6k
        {
261
24.6k
            if (pfnErrorHandler != nullptr)
262
24.6k
            {
263
24.6k
                pfnErrorHandler(eErrClass, err_no, pszMessage);
264
24.6k
            }
265
24.6k
        }
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
24.6k
    }
272
24.6k
}
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
22.9k
{
313
22.9k
    va_list args;
314
315
    // Expand the error message.
316
22.9k
    va_start(args, fmt);
317
22.9k
    CPLErrorV(eErrClass, err_no, fmt, args);
318
22.9k
    va_end(args);
319
22.9k
}
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
22.9k
{
329
22.9k
    CPLErrorContext *psCtx = CPLGetErrorContext();
330
22.9k
    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
22.9k
    if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
362
0
        eErrClass = CE_Warning;
363
364
/* -------------------------------------------------------------------- */
365
/*      Expand the error message                                        */
366
/* -------------------------------------------------------------------- */
367
22.9k
#if defined(HAVE_VSNPRINTF)
368
22.9k
    {
369
22.9k
        va_list wrk_args;
370
371
22.9k
#ifdef va_copy
372
22.9k
        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
22.9k
        int nPreviousSize = 0;
384
22.9k
        if (psCtx->psHandlerStack != nullptr &&
385
0
            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
22.9k
        int nPR = 0;
407
22.9k
        while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
408
22.9k
                                    psCtx->nLastErrMsgMax - nPreviousSize, fmt,
409
22.9k
                                    wrk_args)) == -1 ||
410
22.9k
                nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
411
6
               psCtx->nLastErrMsgMax < 1000000)
412
6
        {
413
6
#ifdef va_copy
414
6
            va_end(wrk_args);
415
6
            va_copy(wrk_args, args);
416
#else
417
            wrk_args = args;
418
#endif
419
6
            psCtx->nLastErrMsgMax *= 3;
420
6
            psCtx = static_cast<CPLErrorContext *>(CPLRealloc(
421
6
                psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
422
6
                           psCtx->nLastErrMsgMax + 1));
423
6
            CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
424
6
        }
425
426
22.9k
        va_end(wrk_args);
427
22.9k
    }
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
22.9k
    char *pszPassword = strstr(psCtx->szLastErrMsg, "password=");
437
22.9k
    if (pszPassword != nullptr)
438
140
    {
439
140
        char *pszIter = pszPassword + strlen("password=");
440
7.20k
        while (*pszIter != ' ' && *pszIter != '\0')
441
7.06k
        {
442
7.06k
            *pszIter = 'X';
443
7.06k
            pszIter++;
444
7.06k
        }
445
140
    }
446
447
    /* -------------------------------------------------------------------- */
448
    /*      If the user provided an handling function, then                 */
449
    /*      call it, otherwise print the error to stderr and return.        */
450
    /* -------------------------------------------------------------------- */
451
22.9k
    psCtx->nLastErrNo = err_no;
452
22.9k
    psCtx->eLastErrType = eErrClass;
453
22.9k
    if (psCtx->nErrorCounter == ~(0U))
454
0
        psCtx->nErrorCounter = 0;
455
22.9k
    else
456
22.9k
        psCtx->nErrorCounter++;
457
458
22.9k
    if (CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr)
459
6.12k
        CPLDebug("CPLError", "%s", psCtx->szLastErrMsg);
460
461
    /* -------------------------------------------------------------------- */
462
    /*      Invoke the current error handler.                               */
463
    /* -------------------------------------------------------------------- */
464
22.9k
    ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
465
466
22.9k
    if (eErrClass == CE_Fatal)
467
0
        abort();
468
22.9k
}
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
3.09k
#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.1k
{
585
27.1k
    CPLErrorContext *psCtx = CPLGetErrorContext();
586
27.1k
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
587
0
        return;
588
27.1k
    const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
589
590
    /* -------------------------------------------------------------------- */
591
    /*      Does this message pass our current criteria?                    */
592
    /* -------------------------------------------------------------------- */
593
27.1k
    if (pszDebug == nullptr || EQUAL(pszDebug, "NO") ||
594
17.3k
        EQUAL(pszDebug, "OFF") || EQUAL(pszDebug, "FALSE") ||
595
17.3k
        EQUAL(pszDebug, "0"))
596
9.78k
    {
597
9.78k
        return;
598
9.78k
    }
599
600
17.3k
    if (!EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, "YES") &&
601
16.7k
        !EQUAL(pszDebug, "TRUE") && !EQUAL(pszDebug, "1") &&
602
16.3k
        !EQUAL(pszDebug, ""))
603
15.9k
    {
604
        // check if value of CPL_DEBUG contains the category
605
15.9k
        const size_t nLen = strlen(pszCategory);
606
607
15.9k
        size_t i = 0;
608
131k
        for (i = 0; pszDebug[i] != '\0'; i++)
609
115k
        {
610
115k
            if (EQUALN(pszCategory, pszDebug + i, nLen))
611
233
                break;
612
115k
        }
613
614
15.9k
        if (pszDebug[i] == '\0')
615
15.6k
            return;
616
15.9k
    }
617
618
    /* -------------------------------------------------------------------- */
619
    /*    Allocate a block for the error.                                   */
620
    /* -------------------------------------------------------------------- */
621
1.69k
    const int ERROR_MAX = 25000;
622
1.69k
    char *pszMessage = static_cast<char *>(VSIMalloc(ERROR_MAX));
623
1.69k
    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
1.69k
    pszMessage[0] = '\0';
632
1.69k
#ifdef TIMESTAMP_DEBUG
633
1.69k
    if (CPLTestBool(CPLGetConfigOption("CPL_TIMESTAMP", "NO")))
634
1.54k
    {
635
1.54k
        static struct CPLTimeVal tvStart;
636
1.54k
        static const auto unused = CPLGettimeofday(&tvStart, nullptr);
637
1.54k
        CPL_IGNORE_RET_VAL(unused);
638
1.54k
        struct CPLTimeVal tv;
639
1.54k
        CPLGettimeofday(&tv, nullptr);
640
1.54k
        strcpy(pszMessage, "[");
641
1.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
1.54k
        if (pszMessage[strlen(pszMessage) - 1] == '\n')
648
1.54k
        {
649
1.54k
            pszMessage[strlen(pszMessage) - 1] = 0;  // blow it out
650
1.54k
        }
651
1.54k
        CPLsnprintf(pszMessage + strlen(pszMessage),
652
1.54k
                    ERROR_MAX - strlen(pszMessage),
653
1.54k
                    "].%04d, %03.04f: ", static_cast<int>(tv.tv_usec / 100),
654
1.54k
                    tv.tv_sec + tv.tv_usec * 1e-6 -
655
1.54k
                        (tvStart.tv_sec + tvStart.tv_usec * 1e-6));
656
1.54k
    }
657
1.69k
#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
1.69k
    strcat(pszMessage, pszCategory);
672
1.69k
    strcat(pszMessage, ": ");
673
674
    /* -------------------------------------------------------------------- */
675
    /*      Format the application provided portion of the debug message.   */
676
    /* -------------------------------------------------------------------- */
677
1.69k
    CPLvsnprintf(pszMessage + strlen(pszMessage),
678
1.69k
                 ERROR_MAX - strlen(pszMessage), pszFormat, args);
679
680
    /* -------------------------------------------------------------------- */
681
    /*      Obfuscate any password in error message                         */
682
    /* -------------------------------------------------------------------- */
683
684
1.69k
    char *pszPassword = strstr(pszMessage, "password=");
685
1.69k
    if (pszPassword != nullptr)
686
45
    {
687
45
        char *pszIter = pszPassword + strlen("password=");
688
2.68k
        while (*pszIter != ' ' && *pszIter != '\0')
689
2.64k
        {
690
2.64k
            *pszIter = 'X';
691
2.64k
            pszIter++;
692
2.64k
        }
693
45
    }
694
695
    /* -------------------------------------------------------------------- */
696
    /*      Invoke the current error handler.                               */
697
    /* -------------------------------------------------------------------- */
698
1.69k
    ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
699
700
1.69k
    VSIFree(pszMessage);
701
1.69k
}
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.1k
{
738
27.1k
    va_list args;
739
27.1k
    va_start(args, pszFormat);
740
27.1k
    CPLvDebug(pszCategory, pszFormat, args);
741
27.1k
    va_end(args);
742
27.1k
}
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
236
{
838
236
    CPLErrorContext *psCtx = CPLGetErrorContext();
839
236
    if (psCtx == nullptr)
840
0
        return;
841
236
    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
236
    psCtx->nLastErrNo = err_no;
866
236
    const size_t size = std::min(static_cast<size_t>(psCtx->nLastErrMsgMax - 1),
867
236
                                 strlen(pszMsg));
868
236
    char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
869
236
    memcpy(pszLastErrMsg, pszMsg, size);
870
236
    pszLastErrMsg[size] = '\0';
871
236
    psCtx->eLastErrType = eErrClass;
872
236
    if (pnErrorCounter)
873
0
        psCtx->nErrorCounter = *pnErrorCounter;
874
236
}
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
 */
883
884
void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
885
                              const char *pszMsg)
886
236
{
887
236
    CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
888
236
}
889
890
/**********************************************************************
891
 *                          CPLGetLastErrorNo()
892
 **********************************************************************/
893
894
/**
895
 * Fetch the last error number.
896
 *
897
 * Fetches the last error number posted with CPLError(), that hasn't
898
 * been cleared by CPLErrorReset().  This is the error number, not the error
899
 * class.
900
 *
901
 * @return the error number of the last error to occur, or CPLE_None (0)
902
 * if there are no posted errors.
903
 */
904
905
CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
906
118
{
907
118
    CPLErrorContext *psCtx = CPLGetErrorContext();
908
118
    if (psCtx == nullptr)
909
0
        return 0;
910
911
118
    return psCtx->nLastErrNo;
912
118
}
913
914
/**********************************************************************
915
 *                          CPLGetLastErrorType()
916
 **********************************************************************/
917
918
/**
919
 * Fetch the last error type.
920
 *
921
 * Fetches the last error type posted with CPLError(), that hasn't
922
 * been cleared by CPLErrorReset().  This is the error class, not the error
923
 * number.
924
 *
925
 * @return the error type of the last error to occur, or CE_None (0)
926
 * if there are no posted errors.
927
 */
928
929
CPLErr CPL_STDCALL CPLGetLastErrorType()
930
236
{
931
236
    CPLErrorContext *psCtx = CPLGetErrorContext();
932
236
    if (psCtx == nullptr)
933
0
        return CE_None;
934
935
236
    return psCtx->eLastErrType;
936
236
}
937
938
/**********************************************************************
939
 *                          CPLGetLastErrorMsg()
940
 **********************************************************************/
941
942
/**
943
 * Get the last error message.
944
 *
945
 * Fetches the last error message posted with CPLError(), that hasn't
946
 * been cleared by CPLErrorReset().  The returned pointer is to an internal
947
 * string that should not be altered or freed.
948
 *
949
 * @return the last error message, or an empty string ("") if there is no
950
 * posted error message.
951
 */
952
953
const char *CPL_STDCALL CPLGetLastErrorMsg()
954
118
{
955
118
    CPLErrorContext *psCtx = CPLGetErrorContext();
956
118
    if (psCtx == nullptr)
957
0
        return "";
958
959
118
    return psCtx->szLastErrMsg;
960
118
}
961
962
/**********************************************************************
963
 *                          CPLGetErrorCounter()
964
 **********************************************************************/
965
966
/**
967
 * Get the error counter
968
 *
969
 * Fetches the number of errors emitted in the current error context,
970
 * since the last call to CPLErrorReset()
971
 *
972
 * @return the error counter.
973
 */
974
975
GUInt32 CPL_STDCALL CPLGetErrorCounter()
976
0
{
977
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
978
0
    if (psCtx == nullptr)
979
0
        return 0;
980
981
0
    return psCtx->nErrorCounter;
982
0
}
983
984
/************************************************************************/
985
/*                       CPLDefaultErrorHandler()                       */
986
/************************************************************************/
987
988
static FILE *fpLog = stderr;
989
static bool bLogInit = false;
990
991
static FILE *CPLfopenUTF8(const char *pszFilename, const char *pszAccess)
992
0
{
993
0
    FILE *f;
994
#ifdef _WIN32
995
    wchar_t *pwszFilename =
996
        CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
997
    wchar_t *pwszAccess =
998
        CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
999
    f = _wfopen(pwszFilename, pwszAccess);
1000
    VSIFree(pwszFilename);
1001
    VSIFree(pwszAccess);
1002
#else
1003
0
    f = fopen(pszFilename, pszAccess);
1004
0
#endif
1005
0
    return f;
1006
0
}
1007
1008
/** Default error handler. */
1009
void CPL_STDCALL CPLDefaultErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1010
                                        const char *pszErrorMsg)
1011
1012
24.6k
{
1013
24.6k
    static int nCount = 0;
1014
24.6k
    static int nMaxErrors = -1;
1015
24.6k
    static const char *pszErrorSeparator = ":";
1016
1017
24.6k
    if (eErrClass != CE_Debug)
1018
22.9k
    {
1019
22.9k
        if (nMaxErrors == -1)
1020
2
        {
1021
2
            nMaxErrors =
1022
2
                atoi(CPLGetConfigOption("CPL_MAX_ERROR_REPORTS", "1000"));
1023
            // If running GDAL as a CustomBuild Command os MSBuild, "ERROR bla:"
1024
            // is considered as failing the job. This is rarely the intended
1025
            // behavior
1026
2
            pszErrorSeparator = CPLGetConfigOption("CPL_ERROR_SEPARATOR", ":");
1027
2
        }
1028
1029
22.9k
        nCount++;
1030
22.9k
        if (nCount > nMaxErrors && nMaxErrors > 0)
1031
20.9k
            return;
1032
22.9k
    }
1033
1034
3.69k
    if (!bLogInit)
1035
2
    {
1036
2
        bLogInit = true;
1037
1038
2
        fpLog = stderr;
1039
2
        const char *pszLog = CPLGetConfigOption("CPL_LOG", nullptr);
1040
2
        if (pszLog != nullptr)
1041
0
        {
1042
0
            const bool bAppend =
1043
0
                CPLGetConfigOption("CPL_LOG_APPEND", nullptr) != nullptr;
1044
0
            const char *pszAccess = bAppend ? "at" : "wt";
1045
0
            fpLog = CPLfopenUTF8(pszLog, pszAccess);
1046
0
            if (fpLog == nullptr)
1047
0
                fpLog = stderr;
1048
0
        }
1049
2
    }
1050
1051
3.69k
    if (eErrClass == CE_Debug)
1052
1.69k
    {
1053
1.69k
#ifndef _WIN32
1054
1.69k
        CPLErrorContext *psCtx = CPLGetErrorContext();
1055
1.69k
        if (psCtx != nullptr && !IS_PREFEFINED_ERROR_CTX(psCtx) &&
1056
1.69k
            fpLog == stderr && CPLIsInteractive(stderr))
1057
0
        {
1058
0
            if (psCtx->bProgressMode)
1059
0
            {
1060
                // Erase the content of the current line
1061
0
                fprintf(stderr, "\r");
1062
0
                fprintf(stderr, "%s", pszErrorMsg);
1063
0
                fflush(stderr);
1064
0
                psCtx->bEmitNewlineBeforeNextDbgMsg = true;
1065
0
            }
1066
0
            else
1067
0
            {
1068
0
                if (psCtx->bEmitNewlineBeforeNextDbgMsg)
1069
0
                {
1070
0
                    psCtx->bEmitNewlineBeforeNextDbgMsg = false;
1071
0
                    fprintf(fpLog, "\n");
1072
0
                }
1073
0
                fprintf(fpLog, "%s\n", pszErrorMsg);
1074
0
            }
1075
0
        }
1076
1.69k
        else
1077
1.69k
#endif
1078
1.69k
        {
1079
1.69k
            fprintf(fpLog, "%s\n", pszErrorMsg);
1080
1.69k
        }
1081
1.69k
    }
1082
2.00k
    else if (eErrClass == CE_Warning)
1083
1.77k
        fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
1084
230
    else
1085
230
        fprintf(fpLog, "ERROR %d%s %s\n", nError, pszErrorSeparator,
1086
230
                pszErrorMsg);
1087
1088
3.69k
    if (eErrClass != CE_Debug && nMaxErrors > 0 && nCount == nMaxErrors)
1089
2
    {
1090
2
        fprintf(fpLog,
1091
2
                "More than %d errors or warnings have been reported. "
1092
2
                "No more will be reported from now.\n",
1093
2
                nMaxErrors);
1094
2
    }
1095
1096
3.69k
    fflush(fpLog);
1097
3.69k
}
1098
1099
/************************************************************************/
1100
/*                        CPLQuietErrorHandler()                        */
1101
/************************************************************************/
1102
1103
/** Error handler that does not do anything, except for debug messages. */
1104
void CPL_STDCALL CPLQuietErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1105
                                      const char *pszErrorMsg)
1106
1107
0
{
1108
0
    if (eErrClass == CE_Debug)
1109
0
        CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
1110
0
}
1111
1112
/************************************************************************/
1113
/*                    CPLQuietWarningsErrorHandler()                    */
1114
/************************************************************************/
1115
1116
/** Error handler that ignores CE_Warning messages. */
1117
void CPL_STDCALL CPLQuietWarningsErrorHandler(CPLErr eErrClass,
1118
                                              CPLErrorNum nError,
1119
                                              const char *pszErrorMsg)
1120
1121
0
{
1122
0
    if (eErrClass != CE_Warning)
1123
0
        CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
1124
0
}
1125
1126
/************************************************************************/
1127
/*                       CPLLoggingErrorHandler()                       */
1128
/************************************************************************/
1129
1130
/** Error handler that logs into the file defined by the CPL_LOG configuration
1131
 * option, or stderr otherwise.
1132
 */
1133
void CPL_STDCALL CPLLoggingErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
1134
                                        const char *pszErrorMsg)
1135
1136
0
{
1137
0
    if (!bLogInit)
1138
0
    {
1139
0
        bLogInit = true;
1140
1141
0
        CPLSetConfigOption("CPL_TIMESTAMP", "ON");
1142
1143
0
        const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr);
1144
1145
0
        fpLog = stderr;
1146
0
        if (cpl_log != nullptr && EQUAL(cpl_log, "OFF"))
1147
0
        {
1148
0
            fpLog = nullptr;
1149
0
        }
1150
0
        else if (cpl_log != nullptr)
1151
0
        {
1152
0
            size_t nPathLen = strlen(cpl_log) + 20;
1153
0
            char *pszPath = static_cast<char *>(CPLMalloc(nPathLen));
1154
0
            strcpy(pszPath, cpl_log);
1155
1156
0
            int i = 0;
1157
0
            while ((fpLog = CPLfopenUTF8(pszPath, "rt")) != nullptr)
1158
0
            {
1159
0
                fclose(fpLog);
1160
1161
                // Generate sequenced log file names, inserting # before ext.
1162
0
                if (strrchr(cpl_log, '.') == nullptr)
1163
0
                {
1164
0
                    snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log, i++,
1165
0
                             ".log");
1166
0
                }
1167
0
                else
1168
0
                {
1169
0
                    size_t pos = 0;
1170
0
                    char *cpl_log_base = CPLStrdup(cpl_log);
1171
0
                    pos = strcspn(cpl_log_base, ".");
1172
0
                    if (pos > 0)
1173
0
                    {
1174
0
                        cpl_log_base[pos] = '\0';
1175
0
                    }
1176
0
                    snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log_base, i++,
1177
0
                             ".log");
1178
0
                    CPLFree(cpl_log_base);
1179
0
                }
1180
0
            }
1181
1182
0
            fpLog = CPLfopenUTF8(pszPath, "wt");
1183
0
            CPLFree(pszPath);
1184
0
        }
1185
0
    }
1186
1187
0
    if (fpLog == nullptr)
1188
0
        return;
1189
1190
0
    if (eErrClass == CE_Debug)
1191
0
        fprintf(fpLog, "%s\n", pszErrorMsg);
1192
0
    else if (eErrClass == CE_Warning)
1193
0
        fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
1194
0
    else
1195
0
        fprintf(fpLog, "ERROR %d: %s\n", nError, pszErrorMsg);
1196
1197
0
    fflush(fpLog);
1198
0
}
1199
1200
/**********************************************************************
1201
 *                      CPLTurnFailureIntoWarning()                   *
1202
 **********************************************************************/
1203
1204
/** Whether failures should be turned into warnings.
1205
 */
1206
void CPLTurnFailureIntoWarning(int bOn)
1207
0
{
1208
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1209
0
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1210
0
    {
1211
0
        fprintf(stderr, "CPLTurnFailureIntoWarning() failed.\n");
1212
0
        return;
1213
0
    }
1214
0
    psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
1215
0
    if (psCtx->nFailureIntoWarning < 0)
1216
0
    {
1217
0
        CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / "
1218
0
                        "CPLTurnFailureIntoWarning(FALSE)");
1219
0
    }
1220
0
}
1221
1222
/**********************************************************************
1223
 *                          CPLSetErrorHandlerEx()                    *
1224
 **********************************************************************/
1225
1226
/**
1227
 * Install custom error handle with user's data. This method is
1228
 * essentially CPLSetErrorHandler with an added pointer to pUserData.
1229
 * The pUserData is not returned in the CPLErrorHandler, however, and
1230
 * must be fetched via CPLGetErrorHandlerUserData.
1231
 *
1232
 * @param pfnErrorHandlerNew new error handler function.
1233
 * @param pUserData User data to carry along with the error context.
1234
 * @return returns the previously installed error handler.
1235
 */
1236
1237
CPLErrorHandler CPL_STDCALL
1238
CPLSetErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew, void *pUserData)
1239
0
{
1240
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1241
0
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1242
0
    {
1243
0
        fprintf(stderr, "CPLSetErrorHandlerEx() failed.\n");
1244
0
        return nullptr;
1245
0
    }
1246
1247
0
    if (psCtx->psHandlerStack != nullptr)
1248
0
    {
1249
0
        CPLDebug("CPL", "CPLSetErrorHandler() called with an error handler on "
1250
0
                        "the local stack.  New error handler will not be used "
1251
0
                        "immediately.");
1252
0
    }
1253
1254
0
    CPLErrorHandler pfnOldHandler = nullptr;
1255
0
    {
1256
0
        CPLMutexHolderD(&hErrorMutex);
1257
1258
0
        pfnOldHandler = pfnErrorHandler;
1259
1260
0
        pfnErrorHandler = pfnErrorHandlerNew;
1261
1262
0
        pErrorHandlerUserData = pUserData;
1263
0
    }
1264
1265
0
    return pfnOldHandler;
1266
0
}
1267
1268
/**********************************************************************
1269
 *                          CPLSetErrorHandler()                      *
1270
 **********************************************************************/
1271
1272
/**
1273
 * Install custom error handler.
1274
 *
1275
 * Allow the library's user to specify an error handler function.
1276
 * A valid error handler is a C function with the following prototype:
1277
 *
1278
 * \code{.cpp}
1279
 *     void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
1280
 * \endcode
1281
 *
1282
 * Pass NULL to come back to the default behavior.  The default behavior
1283
 * (CPLDefaultErrorHandler()) is to write the message to stderr.
1284
 *
1285
 * The msg will be a partially formatted error message not containing the
1286
 * "ERROR %d:" portion emitted by the default handler.  Message formatting
1287
 * is handled by CPLError() before calling the handler.  If the error
1288
 * handler function is passed a CE_Fatal class error and returns, then
1289
 * CPLError() will call abort(). Applications wanting to interrupt this
1290
 * fatal behavior will have to use longjmp(), or a C++ exception to
1291
 * indirectly exit the function.
1292
 *
1293
 * Another standard error handler is CPLQuietErrorHandler() which doesn't
1294
 * make any attempt to report the passed error or warning messages but
1295
 * will process debug messages via CPLDefaultErrorHandler.
1296
 *
1297
 * Note that error handlers set with CPLSetErrorHandler() apply to all
1298
 * threads in an application, while error handlers set with CPLPushErrorHandler
1299
 * are thread-local.  However, any error handlers pushed with
1300
 * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
1301
 * precedence over the global error handlers set with CPLSetErrorHandler().
1302
 * Generally speaking CPLSetErrorHandler() would be used to set a desired
1303
 * global error handler, while CPLPushErrorHandler() would be used to install
1304
 * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
1305
 * error reporting in a limited segment of code.
1306
 *
1307
 * @param pfnErrorHandlerNew new error handler function.
1308
 * @return returns the previously installed error handler.
1309
 */
1310
CPLErrorHandler CPL_STDCALL
1311
CPLSetErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
1312
0
{
1313
0
    return CPLSetErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1314
0
}
1315
1316
/************************************************************************/
1317
/*                        CPLPushErrorHandler()                         */
1318
/************************************************************************/
1319
1320
/**
1321
 * Push a new CPLError handler.
1322
 *
1323
 * This pushes a new error handler on the thread-local error handler
1324
 * stack.  This handler will be used until removed with CPLPopErrorHandler().
1325
 *
1326
 * The CPLSetErrorHandler() docs have further information on how
1327
 * CPLError handlers work.
1328
 *
1329
 * @param pfnErrorHandlerNew new error handler function.
1330
 */
1331
1332
void CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
1333
1334
0
{
1335
0
    CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
1336
0
}
1337
1338
/************************************************************************/
1339
/*                        CPLPushErrorHandlerEx()                       */
1340
/************************************************************************/
1341
1342
/**
1343
 * Push a new CPLError handler with user data on the error context.
1344
 *
1345
 * This pushes a new error handler on the thread-local error handler
1346
 * stack.  This handler will be used until removed with CPLPopErrorHandler().
1347
 * Obtain the user data back by using CPLGetErrorContext().
1348
 *
1349
 * The CPLSetErrorHandler() docs have further information on how
1350
 * CPLError handlers work.
1351
 *
1352
 * @param pfnErrorHandlerNew new error handler function.
1353
 * @param pUserData User data to put on the error context.
1354
 */
1355
void CPL_STDCALL CPLPushErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,
1356
                                       void *pUserData)
1357
1358
0
{
1359
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1360
1361
0
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1362
0
    {
1363
0
        fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
1364
0
        return;
1365
0
    }
1366
1367
0
    CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
1368
0
        CPLMalloc(sizeof(CPLErrorHandlerNode)));
1369
0
    psNode->psNext = psCtx->psHandlerStack;
1370
0
    psNode->pfnHandler = pfnErrorHandlerNew;
1371
0
    psNode->pUserData = pUserData;
1372
0
    psNode->bCatchDebug = true;
1373
0
    psCtx->psHandlerStack = psNode;
1374
0
}
1375
1376
/************************************************************************/
1377
/*                         CPLPopErrorHandler()                         */
1378
/************************************************************************/
1379
1380
/**
1381
 * Pop error handler off stack.
1382
 *
1383
 * Discards the current error handler on the error handler stack, and restores
1384
 * the one in use before the last CPLPushErrorHandler() call.  This method
1385
 * has no effect if there are no error handlers on the current threads error
1386
 * handler stack.
1387
 */
1388
1389
void CPL_STDCALL CPLPopErrorHandler()
1390
1391
0
{
1392
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1393
1394
0
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1395
0
    {
1396
0
        fprintf(stderr, "CPLPopErrorHandler() failed.\n");
1397
0
        return;
1398
0
    }
1399
1400
0
    if (psCtx->psHandlerStack != nullptr)
1401
0
    {
1402
0
        CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
1403
1404
0
        psCtx->psHandlerStack = psNode->psNext;
1405
0
        VSIFree(psNode);
1406
0
    }
1407
0
}
1408
1409
/************************************************************************/
1410
/*                         CPLCallPreviousHandler()                     */
1411
/************************************************************************/
1412
1413
/**
1414
 * Call the previously installed error handler in the error handler stack.
1415
 *
1416
 * Only to be used by a custom error handler that wants to forward events to
1417
 * the previous error handler.
1418
 *
1419
 * @since GDAL 3.8
1420
 */
1421
1422
void CPLCallPreviousHandler(CPLErr eErrClass, CPLErrorNum err_no,
1423
                            const char *pszMsg)
1424
0
{
1425
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1426
1427
0
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1428
0
    {
1429
0
        fprintf(stderr, "CPLCallPreviousHandler() failed.\n");
1430
0
        return;
1431
0
    }
1432
1433
0
    if (psCtx->psHandlerStack != nullptr)
1434
0
    {
1435
0
        CPLErrorHandlerNode *psCurNode = psCtx->psHandlerStack;
1436
0
        psCtx->psHandlerStack = psCurNode->psNext;
1437
0
        if (psCtx->psHandlerStack)
1438
0
        {
1439
0
            CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
1440
0
            psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMsg);
1441
0
            if (psNewCurNode != psCtx->psHandlerStack)
1442
0
            {
1443
0
                fprintf(stderr, "CPLCallPreviousHandler() has detected that a "
1444
0
                                "previous error handler messed up with the "
1445
0
                                "error stack. Chaos guaranteed!\n");
1446
0
            }
1447
0
        }
1448
0
        else
1449
0
            CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
1450
0
        psCtx->psHandlerStack = psCurNode;
1451
0
    }
1452
0
    else
1453
0
    {
1454
0
        CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
1455
0
    }
1456
0
}
1457
1458
/************************************************************************/
1459
/*                 CPLSetCurrentErrorHandlerCatchDebug()                */
1460
/************************************************************************/
1461
1462
/**
1463
 * Set if the current error handler should intercept debug messages, or if
1464
 * they should be processed by the previous handler.
1465
 *
1466
 * By default when installing a custom error handler, this one intercepts
1467
 * debug messages. In some cases, this might not be desirable and the user
1468
 * would prefer that the previous installed handler (or the default one if no
1469
 * previous installed handler exists in the stack) deal with it. In which
1470
 * case, this function should be called with bCatchDebug = FALSE.
1471
 *
1472
 * @param bCatchDebug FALSE if the current error handler should not intercept
1473
 * debug messages
1474
 */
1475
1476
void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)
1477
0
{
1478
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1479
1480
0
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
1481
0
    {
1482
0
        fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
1483
0
        return;
1484
0
    }
1485
1486
0
    if (psCtx->psHandlerStack != nullptr)
1487
0
        psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
1488
0
    else
1489
0
        gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
1490
0
}
1491
1492
/************************************************************************/
1493
/*                             _CPLAssert()                             */
1494
/*                                                                      */
1495
/*      This function is called only when an assertion fails.           */
1496
/************************************************************************/
1497
1498
/**
1499
 * Report failure of a logical assertion.
1500
 *
1501
 * Applications would normally use the CPLAssert() macro which expands
1502
 * into code calling _CPLAssert() only if the condition fails.  _CPLAssert()
1503
 * will generate a CE_Fatal error call to CPLError(), indicating the file
1504
 * name, and line number of the failed assertion, as well as containing
1505
 * the assertion itself.
1506
 *
1507
 * There is no reason for application code to call _CPLAssert() directly.
1508
 */
1509
1510
void CPL_STDCALL _CPLAssert(const char *pszExpression, const char *pszFile,
1511
                            int iLine)
1512
1513
0
{
1514
0
    CPLError(CE_Fatal, CPLE_AssertionFailed,
1515
0
             "Assertion `%s' failed "
1516
0
             "in file `%s', line %d",
1517
0
             pszExpression, pszFile, iLine);
1518
1519
    // Just to please compiler so it is aware the function does not return.
1520
0
    abort();
1521
0
}
1522
1523
/************************************************************************/
1524
/*                       CPLCleanupErrorMutex()                         */
1525
/************************************************************************/
1526
1527
void CPLCleanupErrorMutex()
1528
0
{
1529
0
    if (hErrorMutex != nullptr)
1530
0
    {
1531
0
        CPLDestroyMutex(hErrorMutex);
1532
0
        hErrorMutex = nullptr;
1533
0
    }
1534
0
    if (fpLog != nullptr && fpLog != stderr)
1535
0
    {
1536
0
        fclose(fpLog);
1537
0
        fpLog = nullptr;
1538
0
        bLogInit = false;
1539
0
    }
1540
0
}
1541
1542
bool CPLIsDefaultErrorHandlerAndCatchDebug()
1543
0
{
1544
0
    CPLErrorContext *psCtx = CPLGetErrorContext();
1545
0
    return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
1546
0
           gbCatchDebug && pfnErrorHandler == CPLDefaultErrorHandler;
1547
0
}
1548
1549
/************************************************************************/
1550
/*               CPLErrorStateBackuper::CPLErrorStateBackuper()         */
1551
/************************************************************************/
1552
1553
CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
1554
0
    : m_nLastErrorNum(CPLGetLastErrorNo()),
1555
0
      m_nLastErrorType(CPLGetLastErrorType()),
1556
0
      m_osLastErrorMsg(CPLGetLastErrorMsg()),
1557
0
      m_nLastErrorCounter(CPLGetErrorCounter()),
1558
      m_poErrorHandlerPusher(
1559
0
          hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
1560
0
                   : nullptr)
1561
0
{
1562
0
}
1563
1564
/************************************************************************/
1565
/*               CPLErrorStateBackuper::~CPLErrorStateBackuper()        */
1566
/************************************************************************/
1567
1568
CPLErrorStateBackuper::~CPLErrorStateBackuper()
1569
0
{
1570
0
    CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
1571
0
                     m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
1572
0
}
1573
1574
/*! @cond Doxygen_Suppress */
1575
1576
/************************************************************************/
1577
/*                CPLErrorAccumulator::Context::~Context()              */
1578
/************************************************************************/
1579
1580
CPLErrorAccumulator::Context::~Context()
1581
0
{
1582
0
    CPLPopErrorHandler();
1583
0
}
1584
1585
/************************************************************************/
1586
/*             CPLErrorAccumulator::InstallForCurrentScope()            */
1587
/************************************************************************/
1588
1589
CPLErrorAccumulator::Context CPLErrorAccumulator::InstallForCurrentScope()
1590
0
{
1591
0
    CPLPushErrorHandlerEx(CPLErrorAccumulator::Accumulator, this);
1592
0
    return CPLErrorAccumulator::Context();
1593
0
}
1594
1595
/************************************************************************/
1596
/*                    CPLErrorAccumulator::ReplayErrors()               */
1597
/************************************************************************/
1598
1599
void CPLErrorAccumulator::ReplayErrors()
1600
0
{
1601
0
    std::lock_guard oLock(mutex);
1602
0
    for (const auto &err : errors)
1603
0
    {
1604
0
        CPLError(err.type, err.no, "%s", err.msg.c_str());
1605
0
    }
1606
0
}
1607
1608
/************************************************************************/
1609
/*                 CPLErrorAccumulator::Accumulator()                   */
1610
/************************************************************************/
1611
1612
/* static */ void CPL_STDCALL CPLErrorAccumulator::Accumulator(CPLErr eErr,
1613
                                                               CPLErrorNum no,
1614
                                                               const char *msg)
1615
0
{
1616
0
    if (eErr != CE_Debug)
1617
0
    {
1618
0
        CPLErrorAccumulator *pThis =
1619
0
            static_cast<CPLErrorAccumulator *>(CPLGetErrorHandlerUserData());
1620
0
        std::lock_guard oLock(pThis->mutex);
1621
0
        pThis->errors.push_back(
1622
0
            CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
1623
0
    }
1624
0
}
1625
1626
/*! @endcond */