• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 15992523769

01 Jul 2025 07:16AM UTC coverage: 71.09% (-0.004%) from 71.094%
15992523769

Pull #12682

github

web-flow
Merge 1383a7df3 into f6ed9706f
Pull Request #12682: Bump msys2/setup-msys2 from 2.27.0 to 2.28.0

574092 of 807557 relevant lines covered (71.09%)

250020.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.02
/port/cpl_error.cpp
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
    (psCtx == &sNoErrorContext || psCtx == &sWarningContext ||                 \
86
     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)
642,700✔
96
{
97
    return psCtxt->szLastErrMsg;
642,700✔
98
}
99

100
/************************************************************************/
101
/*                         CPLGetErrorContext()                         */
102
/************************************************************************/
103

104
static CPLErrorContext *CPLGetErrorContext()
48,423,600✔
105

106
{
107
    int bError = FALSE;
48,423,600✔
108
    CPLErrorContext *psCtx = reinterpret_cast<CPLErrorContext *>(
109
        CPLGetTLSEx(CTLS_ERRORCONTEXT, &bError));
48,423,600✔
110
    if (bError)
48,422,900✔
111
        return nullptr;
×
112

113
    if (psCtx == nullptr)
48,422,900✔
114
    {
115
        psCtx = static_cast<CPLErrorContext *>(
116
            VSICalloc(sizeof(CPLErrorContext), 1));
3,295✔
117
        if (psCtx == nullptr)
3,293✔
118
        {
119
            fprintf(stderr, "Out of memory attempting to report error.\n");
×
120
            return nullptr;
×
121
        }
122
        psCtx->eLastErrType = CE_None;
3,293✔
123
        psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
3,293✔
124
        CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
3,293✔
125
    }
126

127
    return psCtx;
48,422,500✔
128
}
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)
6,002,690✔
148
{
149
    // get the current threadlocal or global error context user data
150
    CPLErrorContext *psCtx = CPLGetErrorContext();
6,002,690✔
151
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
6,002,690✔
152
        abort();
×
153
    return reinterpret_cast<void *>(psCtx->psHandlerStack
6,002,690✔
154
                                        ? psCtx->psHandlerStack->pUserData
6,002,690✔
155
                                        : pErrorHandlerUserData);
6,002,690✔
156
}
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
{
177
    CPLErrorContext *psCtx = CPLGetErrorContext();
×
178

179
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
×
180
    {
181
        fprintf(stderr, "CPLGetErrorHandler() failed.\n");
×
182
        if (ppUserData)
×
183
            *ppUserData = nullptr;
×
184
        return CPLDefaultErrorHandler;
×
185
    }
186

187
    if (psCtx->psHandlerStack != nullptr)
×
188
    {
189
        if (ppUserData)
×
190
            *ppUserData = psCtx->psHandlerStack->pUserData;
×
191
        return psCtx->psHandlerStack->pfnHandler;
×
192
    }
193

194
    CPLMutexHolderD(&hErrorMutex);
×
195
    if (ppUserData)
×
196
        *ppUserData = pErrorHandlerUserData;
×
197
    return pfnErrorHandler;
×
198
}
199

200
/************************************************************************/
201
/*                          ApplyErrorHandler()                         */
202
/************************************************************************/
203

204
static void ApplyErrorHandler(CPLErrorContext *psCtx, CPLErr eErrClass,
98,493✔
205
                              CPLErrorNum err_no, const char *pszMessage)
206
{
207
    bool bProcessed = false;
98,493✔
208

209
    if (psCtx->psHandlerStack != nullptr)
98,493✔
210
    {
211
        // iterate through the threadlocal handler stack
212
        if ((eErrClass != CE_Debug) || psCtx->psHandlerStack->bCatchDebug)
59,140✔
213
        {
214
            // call the error handler
215
            CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
59,063✔
216
            psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMessage);
59,063✔
217
            if (psNewCurNode != psCtx->psHandlerStack)
59,062✔
218
            {
219
                fprintf(stderr, "ApplyErrorHandler() has detected that a "
×
220
                                "previous error handler messed up with the "
221
                                "error stack. Chaos guaranteed!\n");
222
            }
223
            bProcessed = true;
59,063✔
224
        }
225
        else
226
        {
227
            // need to iterate to a parent handler for debug messages
228
            CPLErrorHandlerNode *psNode = psCtx->psHandlerStack->psNext;
77✔
229
            while (psNode != nullptr)
77✔
230
            {
231
                if (psNode->bCatchDebug)
76✔
232
                {
233
                    CPLErrorHandlerNode *psBackupCurNode =
76✔
234
                        psCtx->psHandlerStack;
235
                    psCtx->psHandlerStack = psNode;
76✔
236
                    CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
76✔
237
                    psNode->pfnHandler(eErrClass, err_no, pszMessage);
76✔
238
                    // cppcheck-suppress knownConditionTrueFalse
239
                    if (psNewCurNode != psCtx->psHandlerStack)
76✔
240
                    {
241
                        fprintf(stderr,
×
242
                                "ApplyErrorHandler() has detected that a "
243
                                "previous error handler messed up with the "
244
                                "error stack. Chaos guaranteed!\n");
245
                    }
246
                    psCtx->psHandlerStack = psBackupCurNode;
76✔
247
                    bProcessed = true;
76✔
248
                    break;
76✔
249
                }
250
                psNode = psNode->psNext;
×
251
            }
252
        }
253
    }
254

255
    if (!bProcessed)
98,493✔
256
    {
257
        // hit the global error handler
258
        CPLMutexHolderD(&hErrorMutex);
78,708✔
259
        if ((eErrClass != CE_Debug) || gbCatchDebug)
39,354✔
260
        {
261
            if (pfnErrorHandler != nullptr)
39,352✔
262
            {
263
                pfnErrorHandler(eErrClass, err_no, pszMessage);
39,350✔
264
            }
265
        }
266
        else /* if( eErrClass == CE_Debug ) */
267
        {
268
            // for CPLDebug messages we propagate to the default error handler
269
            CPLDefaultErrorHandler(eErrClass, err_no, pszMessage);
2✔
270
        }
271
    }
272
}
98,493✔
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,
96,714✔
311
              CPL_FORMAT_STRING(const char *fmt), ...)
312
{
313
    va_list args;
314

315
    // Expand the error message.
316
    va_start(args, fmt);
96,714✔
317
    CPLErrorV(eErrClass, err_no, fmt, args);
96,714✔
318
    va_end(args);
96,715✔
319
}
96,715✔
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,
97,747✔
327
               va_list args)
328
{
329
    CPLErrorContext *psCtx = CPLGetErrorContext();
97,747✔
330
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
97,746✔
331
    {
332
        int bMemoryError = FALSE;
×
333
        if (eErrClass == CE_Warning)
×
334
        {
335
            CPLSetTLSWithFreeFuncEx(
×
336
                CTLS_ERRORCONTEXT,
337
                reinterpret_cast<void *>(
338
                    const_cast<CPLErrorContext *>(&sWarningContext)),
339
                nullptr, &bMemoryError);
340
        }
341
        else if (eErrClass == CE_Failure)
×
342
        {
343
            CPLSetTLSWithFreeFuncEx(
×
344
                CTLS_ERRORCONTEXT,
345
                reinterpret_cast<void *>(
346
                    const_cast<CPLErrorContext *>(&sFailureContext)),
347
                nullptr, &bMemoryError);
348
        }
349

350
        // TODO: Is it possible to move the entire szShortMessage under the if
351
        // pfnErrorHandler?
352
        char szShortMessage[80] = {};
×
353
        CPLvsnprintf(szShortMessage, sizeof(szShortMessage), fmt, args);
×
354

355
        CPLMutexHolderD(&hErrorMutex);
×
356
        if (pfnErrorHandler != nullptr)
×
357
            pfnErrorHandler(eErrClass, err_no, szShortMessage);
×
358
        return;
×
359
    }
360

361
    if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
97,746✔
362
        eErrClass = CE_Warning;
5✔
363

364
/* -------------------------------------------------------------------- */
365
/*      Expand the error message                                        */
366
/* -------------------------------------------------------------------- */
367
#if defined(HAVE_VSNPRINTF)
368
    {
369
        va_list wrk_args;
370

371
#ifdef va_copy
372
        va_copy(wrk_args, args);
97,746✔
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
        int nPreviousSize = 0;
97,746✔
384
        if (psCtx->psHandlerStack != nullptr &&
156,737✔
385
            EQUAL(CPLGetConfigOption("CPL_ACCUM_ERROR_MSG", ""), "ON"))
58,990✔
386
        {
387
            nPreviousSize = static_cast<int>(strlen(psCtx->szLastErrMsg));
×
388
            if (nPreviousSize)
×
389
            {
390
                if (nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax)
×
391
                {
392
                    psCtx->nLastErrMsgMax *= 3;
×
393
                    psCtx = static_cast<CPLErrorContext *>(
394
                        CPLRealloc(psCtx, sizeof(CPLErrorContext) -
×
395
                                              DEFAULT_LAST_ERR_MSG_SIZE +
396
                                              psCtx->nLastErrMsgMax + 1));
×
397
                    CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
×
398
                }
399
                char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
×
400
                pszLastErrMsg[nPreviousSize] = '\n';
×
401
                pszLastErrMsg[nPreviousSize + 1] = '\0';
×
402
                nPreviousSize++;
×
403
            }
404
        }
405

406
        int nPR = 0;
97,747✔
407
        while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
17✔
408
                                    psCtx->nLastErrMsgMax - nPreviousSize, fmt,
97,764✔
409
                                    wrk_args)) == -1 ||
97,753✔
410
                nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
97,786✔
411
               psCtx->nLastErrMsgMax < 1000000)
25✔
412
        {
413
#ifdef va_copy
414
            va_end(wrk_args);
17✔
415
            va_copy(wrk_args, args);
17✔
416
#else
417
            wrk_args = args;
418
#endif
419
            psCtx->nLastErrMsgMax *= 3;
17✔
420
            psCtx = static_cast<CPLErrorContext *>(CPLRealloc(
34✔
421
                psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
422
                           psCtx->nLastErrMsgMax + 1));
17✔
423
            CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
17✔
424
        }
425

426
        va_end(wrk_args);
97,744✔
427
    }
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
    char *pszPassword = strstr(psCtx->szLastErrMsg, "password=");
97,744✔
437
    if (pszPassword != nullptr)
97,744✔
438
    {
439
        char *pszIter = pszPassword + strlen("password=");
×
440
        while (*pszIter != ' ' && *pszIter != '\0')
×
441
        {
442
            *pszIter = 'X';
×
443
            pszIter++;
×
444
        }
445
    }
446

447
    /* -------------------------------------------------------------------- */
448
    /*      If the user provided an handling function, then                 */
449
    /*      call it, otherwise print the error to stderr and return.        */
450
    /* -------------------------------------------------------------------- */
451
    psCtx->nLastErrNo = err_no;
97,744✔
452
    psCtx->eLastErrType = eErrClass;
97,744✔
453
    if (psCtx->nErrorCounter == ~(0U))
97,744✔
454
        psCtx->nErrorCounter = 0;
×
455
    else
456
        psCtx->nErrorCounter++;
97,744✔
457

458
    if (CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr)
97,744✔
459
        CPLDebug("CPLError", "%s", psCtx->szLastErrMsg);
×
460

461
    /* -------------------------------------------------------------------- */
462
    /*      Invoke the current error handler.                               */
463
    /* -------------------------------------------------------------------- */
464
    ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
97,747✔
465

466
    if (eErrClass == CE_Fatal)
97,746✔
467
        abort();
×
468
}
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
{
492
    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
    if (!bInEmergencyError)
×
497
    {
498
        bInEmergencyError = true;
×
499
        CPLErrorContext *psCtx =
500
            static_cast<CPLErrorContext *>(CPLGetTLS(CTLS_ERRORCONTEXT));
×
501

502
        ApplyErrorHandler(psCtx, CE_Fatal, CPLE_AppDefined, pszMessage);
×
503
    }
504

505
    // Ultimate fallback.
506
    fprintf(stderr, "FATAL: %s\n", pszMessage);
×
507

508
    abort();
×
509
}
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
#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,
660,050✔
583
                      CPL_FORMAT_STRING(const char *pszFormat), va_list args)
584
{
585
    CPLErrorContext *psCtx = CPLGetErrorContext();
660,050✔
586
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
660,015✔
587
        return;
×
588
    const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
660,050✔
589

590
    /* -------------------------------------------------------------------- */
591
    /*      Does this message pass our current criteria?                    */
592
    /* -------------------------------------------------------------------- */
593
    if (pszDebug == nullptr || EQUAL(pszDebug, "NO") ||
660,078✔
594
        EQUAL(pszDebug, "OFF") || EQUAL(pszDebug, "FALSE") ||
829✔
595
        EQUAL(pszDebug, "0"))
810✔
596
    {
597
        return;
659,269✔
598
    }
599

600
    if (!EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, "YES") &&
809✔
601
        !EQUAL(pszDebug, "TRUE") && !EQUAL(pszDebug, "1") &&
121✔
602
        !EQUAL(pszDebug, ""))
115✔
603
    {
604
        // check if value of CPL_DEBUG contains the category
605
        const size_t nLen = strlen(pszCategory);
114✔
606

607
        size_t i = 0;
114✔
608
        for (i = 0; pszDebug[i] != '\0'; i++)
813✔
609
        {
610
            if (EQUALN(pszCategory, pszDebug + i, nLen))
750✔
611
                break;
51✔
612
        }
613

614
        if (pszDebug[i] == '\0')
114✔
615
            return;
63✔
616
    }
617

618
    /* -------------------------------------------------------------------- */
619
    /*    Allocate a block for the error.                                   */
620
    /* -------------------------------------------------------------------- */
621
    const int ERROR_MAX = 25000;
746✔
622
    char *pszMessage = static_cast<char *>(VSIMalloc(ERROR_MAX));
746✔
623
    if (pszMessage == nullptr)
746✔
624
        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
    pszMessage[0] = '\0';
746✔
632
#ifdef TIMESTAMP_DEBUG
633
    if (CPLTestBool(CPLGetConfigOption("CPL_TIMESTAMP", "NO")))
746✔
634
    {
635
        static struct CPLTimeVal tvStart;
636
        static const auto unused = CPLGettimeofday(&tvStart, nullptr);
4✔
637
        CPL_IGNORE_RET_VAL(unused);
4✔
638
        struct CPLTimeVal tv;
639
        CPLGettimeofday(&tv, nullptr);
4✔
640
        strcpy(pszMessage, "[");
4✔
641
        strcat(pszMessage, VSICTime(static_cast<unsigned long>(tv.tv_sec)));
4✔
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
        if (pszMessage[strlen(pszMessage) - 1] == '\n')
4✔
648
        {
649
            pszMessage[strlen(pszMessage) - 1] = 0;  // blow it out
4✔
650
        }
651
        CPLsnprintf(pszMessage + strlen(pszMessage),
4✔
652
                    ERROR_MAX - strlen(pszMessage),
4✔
653
                    "].%04d, %03.04f: ", static_cast<int>(tv.tv_usec / 100),
4✔
654
                    tv.tv_sec + tv.tv_usec * 1e-6 -
4✔
655
                        (tvStart.tv_sec + tvStart.tv_usec * 1e-6));
4✔
656
    }
657
#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
    strcat(pszMessage, pszCategory);
746✔
672
    strcat(pszMessage, ": ");
746✔
673

674
    /* -------------------------------------------------------------------- */
675
    /*      Format the application provided portion of the debug message.   */
676
    /* -------------------------------------------------------------------- */
677
    CPLvsnprintf(pszMessage + strlen(pszMessage),
746✔
678
                 ERROR_MAX - strlen(pszMessage), pszFormat, args);
746✔
679

680
    /* -------------------------------------------------------------------- */
681
    /*      Obfuscate any password in error message                         */
682
    /* -------------------------------------------------------------------- */
683

684
    char *pszPassword = strstr(pszMessage, "password=");
746✔
685
    if (pszPassword != nullptr)
746✔
686
    {
687
        char *pszIter = pszPassword + strlen("password=");
×
688
        while (*pszIter != ' ' && *pszIter != '\0')
×
689
        {
690
            *pszIter = 'X';
×
691
            pszIter++;
×
692
        }
693
    }
694

695
    /* -------------------------------------------------------------------- */
696
    /*      Invoke the current error handler.                               */
697
    /* -------------------------------------------------------------------- */
698
    ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
746✔
699

700
    VSIFree(pszMessage);
746✔
701
}
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),
660,060✔
735
              ...)
736

737
{
738
    va_list args;
739
    va_start(args, pszFormat);
660,060✔
740
    CPLvDebug(pszCategory, pszFormat, args);
660,060✔
741
    va_end(args);
660,076✔
742
}
660,076✔
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,
2✔
780
                      CPL_FORMAT_STRING(const char *pszFormat), ...)
781

782
{
783
    CPLErrorContext *psCtx = CPLGetErrorContext();
2✔
784
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
2✔
785
        return;
×
786

787
    psCtx->bProgressMode = true;
2✔
788

789
    va_list args;
790
    va_start(args, pszFormat);
2✔
791
    CPLvDebug(pszCategory, pszFormat, args);
2✔
792
    va_end(args);
2✔
793

794
    psCtx->bProgressMode = false;
2✔
795
}
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()
6,847,130✔
810
{
811
    CPLErrorContext *psCtx = CPLGetErrorContext();
6,847,130✔
812
    if (psCtx == nullptr)
6,847,130✔
813
        return;
×
814
    if (IS_PREFEFINED_ERROR_CTX(psCtx))
6,847,130✔
815
    {
816
        int bMemoryError = FALSE;
1✔
817
        CPLSetTLSWithFreeFuncEx(
1✔
818
            CTLS_ERRORCONTEXT,
819
            reinterpret_cast<void *>(
820
                const_cast<CPLErrorContext *>(&sNoErrorContext)),
821
            nullptr, &bMemoryError);
822
        return;
×
823
    }
824

825
    psCtx->nLastErrNo = CPLE_None;
6,847,130✔
826
    psCtx->szLastErrMsg[0] = '\0';
6,847,130✔
827
    psCtx->eLastErrType = CE_None;
6,847,130✔
828
    psCtx->nErrorCounter = 0;
6,847,130✔
829
}
830

831
/**********************************************************************
832
 *                       CPLErrorSetState()
833
 **********************************************************************/
834

835
void CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no, const char *pszMsg,
642,731✔
836
                      const GUInt32 *pnErrorCounter)
837
{
838
    CPLErrorContext *psCtx = CPLGetErrorContext();
642,731✔
839
    if (psCtx == nullptr)
642,705✔
840
        return;
×
841
    if (IS_PREFEFINED_ERROR_CTX(psCtx))
642,705✔
842
    {
843
        int bMemoryError = FALSE;
20✔
844
        if (eErrClass == CE_None)
20✔
845
            CPLSetTLSWithFreeFuncEx(
×
846
                CTLS_ERRORCONTEXT,
847
                reinterpret_cast<void *>(
848
                    const_cast<CPLErrorContext *>(&sNoErrorContext)),
849
                nullptr, &bMemoryError);
850
        else if (eErrClass == CE_Warning)
20✔
851
            CPLSetTLSWithFreeFuncEx(
×
852
                CTLS_ERRORCONTEXT,
853
                reinterpret_cast<void *>(
854
                    const_cast<CPLErrorContext *>(&sWarningContext)),
855
                nullptr, &bMemoryError);
856
        else if (eErrClass == CE_Failure)
20✔
857
            CPLSetTLSWithFreeFuncEx(
×
858
                CTLS_ERRORCONTEXT,
859
                reinterpret_cast<void *>(
860
                    const_cast<CPLErrorContext *>(&sFailureContext)),
861
                nullptr, &bMemoryError);
862
        return;
×
863
    }
864

865
    psCtx->nLastErrNo = err_no;
642,685✔
866
    const size_t size = std::min(static_cast<size_t>(psCtx->nLastErrMsgMax - 1),
1,285,380✔
867
                                 strlen(pszMsg));
642,685✔
868
    char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
642,699✔
869
    memcpy(pszLastErrMsg, pszMsg, size);
642,692✔
870
    pszLastErrMsg[size] = '\0';
642,692✔
871
    psCtx->eLastErrType = eErrClass;
642,692✔
872
    if (pnErrorCounter)
642,692✔
873
        psCtx->nErrorCounter = *pnErrorCounter;
114,852✔
874
}
875

876
/**
877
 * Restore an error state, without emitting an error.
878
 *
879
 * Can be useful if a routine might call CPLErrorReset() and one wants to
880
 * preserve the previous error state.
881
 *
882
 * @since GDAL 2.0
883
 */
884

885
void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
527,870✔
886
                              const char *pszMsg)
887
{
888
    CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
527,870✔
889
}
527,869✔
890

891
/**********************************************************************
892
 *                          CPLGetLastErrorNo()
893
 **********************************************************************/
894

895
/**
896
 * Fetch the last error number.
897
 *
898
 * Fetches the last error number posted with CPLError(), that hasn't
899
 * been cleared by CPLErrorReset().  This is the error number, not the error
900
 * class.
901
 *
902
 * @return the error number of the last error to occur, or CPLE_None (0)
903
 * if there are no posted errors.
904
 */
905

906
CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
752,521✔
907
{
908
    CPLErrorContext *psCtx = CPLGetErrorContext();
752,521✔
909
    if (psCtx == nullptr)
752,735✔
910
        return 0;
×
911

912
    return psCtx->nLastErrNo;
752,735✔
913
}
914

915
/**********************************************************************
916
 *                          CPLGetLastErrorType()
917
 **********************************************************************/
918

919
/**
920
 * Fetch the last error type.
921
 *
922
 * Fetches the last error type posted with CPLError(), that hasn't
923
 * been cleared by CPLErrorReset().  This is the error class, not the error
924
 * number.
925
 *
926
 * @return the error type of the last error to occur, or CE_None (0)
927
 * if there are no posted errors.
928
 */
929

930
CPLErr CPL_STDCALL CPLGetLastErrorType()
9,433,590✔
931
{
932
    CPLErrorContext *psCtx = CPLGetErrorContext();
9,433,590✔
933
    if (psCtx == nullptr)
9,433,570✔
934
        return CE_None;
×
935

936
    return psCtx->eLastErrType;
9,433,570✔
937
}
938

939
/**********************************************************************
940
 *                          CPLGetLastErrorMsg()
941
 **********************************************************************/
942

943
/**
944
 * Get the last error message.
945
 *
946
 * Fetches the last error message posted with CPLError(), that hasn't
947
 * been cleared by CPLErrorReset().  The returned pointer is to an internal
948
 * string that should not be altered or freed.
949
 *
950
 * @return the last error message, or an empty string ("") if there is no
951
 * posted error message.
952
 */
953

954
const char *CPL_STDCALL CPLGetLastErrorMsg()
377,127✔
955
{
956
    CPLErrorContext *psCtx = CPLGetErrorContext();
377,127✔
957
    if (psCtx == nullptr)
377,106✔
958
        return "";
×
959

960
    return psCtx->szLastErrMsg;
377,106✔
961
}
962

963
/**********************************************************************
964
 *                          CPLGetErrorCounter()
965
 **********************************************************************/
966

967
/**
968
 * Get the error counter
969
 *
970
 * Fetches the number of errors emitted in the current error context,
971
 * since the last call to CPLErrorReset()
972
 *
973
 * @return the error counter.
974
 * @since GDAL 2.3
975
 */
976

977
GUInt32 CPL_STDCALL CPLGetErrorCounter()
11,062,400✔
978
{
979
    CPLErrorContext *psCtx = CPLGetErrorContext();
11,062,400✔
980
    if (psCtx == nullptr)
11,060,000✔
981
        return 0;
×
982

983
    return psCtx->nErrorCounter;
11,060,000✔
984
}
985

986
/************************************************************************/
987
/*                       CPLDefaultErrorHandler()                       */
988
/************************************************************************/
989

990
static FILE *fpLog = stderr;
991
static bool bLogInit = false;
992

993
static FILE *CPLfopenUTF8(const char *pszFilename, const char *pszAccess)
1✔
994
{
995
    FILE *f;
996
#ifdef _WIN32
997
    wchar_t *pwszFilename =
998
        CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
999
    wchar_t *pwszAccess =
1000
        CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
1001
    f = _wfopen(pwszFilename, pwszAccess);
1002
    VSIFree(pwszFilename);
1003
    VSIFree(pwszAccess);
1004
#else
1005
    f = fopen(pszFilename, pszAccess);
1✔
1006
#endif
1007
    return f;
1✔
1008
}
1009

1010
/** Default error handler. */
1011
void CPL_STDCALL CPLDefaultErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
58,402✔
1012
                                        const char *pszErrorMsg)
1013

1014
{
1015
    static int nCount = 0;
1016
    static int nMaxErrors = -1;
1017
    static const char *pszErrorSeparator = ":";
1018

1019
    if (eErrClass != CE_Debug)
58,402✔
1020
    {
1021
        if (nMaxErrors == -1)
57,802✔
1022
        {
1023
            nMaxErrors =
225✔
1024
                atoi(CPLGetConfigOption("CPL_MAX_ERROR_REPORTS", "1000"));
225✔
1025
            // If running GDAL as a CustomBuild Command os MSBuild, "ERROR bla:"
1026
            // is considered as failing the job. This is rarely the intended
1027
            // behavior
1028
            pszErrorSeparator = CPLGetConfigOption("CPL_ERROR_SEPARATOR", ":");
225✔
1029
        }
1030

1031
        nCount++;
57,802✔
1032
        if (nCount > nMaxErrors && nMaxErrors > 0)
57,802✔
1033
            return;
54,486✔
1034
    }
1035

1036
    if (!bLogInit)
3,916✔
1037
    {
1038
        bLogInit = true;
237✔
1039

1040
        fpLog = stderr;
237✔
1041
        const char *pszLog = CPLGetConfigOption("CPL_LOG", nullptr);
237✔
1042
        if (pszLog != nullptr)
237✔
1043
        {
1044
            const bool bAppend =
1045
                CPLGetConfigOption("CPL_LOG_APPEND", nullptr) != nullptr;
1✔
1046
            const char *pszAccess = bAppend ? "at" : "wt";
1✔
1047
            fpLog = CPLfopenUTF8(pszLog, pszAccess);
1✔
1048
            if (fpLog == nullptr)
1✔
1049
                fpLog = stderr;
×
1050
        }
1051
    }
1052

1053
    if (eErrClass == CE_Debug)
3,916✔
1054
    {
1055
#ifndef _WIN32
1056
        CPLErrorContext *psCtx = CPLGetErrorContext();
600✔
1057
        if (psCtx != nullptr && !IS_PREFEFINED_ERROR_CTX(psCtx) &&
600✔
1058
            fpLog == stderr && CPLIsInteractive(stderr))
1,200✔
1059
        {
1060
            if (psCtx->bProgressMode)
×
1061
            {
1062
                // Erase the content of the current line
1063
                fprintf(stderr, "\r");
×
1064
                fprintf(stderr, "%s", pszErrorMsg);
×
1065
                fflush(stderr);
×
1066
                psCtx->bEmitNewlineBeforeNextDbgMsg = true;
×
1067
            }
1068
            else
1069
            {
1070
                if (psCtx->bEmitNewlineBeforeNextDbgMsg)
×
1071
                {
1072
                    psCtx->bEmitNewlineBeforeNextDbgMsg = false;
×
1073
                    fprintf(fpLog, "\n");
×
1074
                }
1075
                fprintf(fpLog, "%s\n", pszErrorMsg);
×
1076
            }
1077
        }
1078
        else
1079
#endif
1080
        {
1081
            fprintf(fpLog, "%s\n", pszErrorMsg);
600✔
1082
        }
1083
    }
1084
    else if (eErrClass == CE_Warning)
3,316✔
1085
        fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
2,576✔
1086
    else
1087
        fprintf(fpLog, "ERROR %d%s %s\n", nError, pszErrorSeparator,
740✔
1088
                pszErrorMsg);
1089

1090
    if (eErrClass != CE_Debug && nMaxErrors > 0 && nCount == nMaxErrors)
3,916✔
1091
    {
1092
        fprintf(fpLog,
2✔
1093
                "More than %d errors or warnings have been reported. "
1094
                "No more will be reported from now.\n",
1095
                nMaxErrors);
1096
    }
1097

1098
    fflush(fpLog);
3,916✔
1099
}
1100

1101
/************************************************************************/
1102
/*                        CPLQuietErrorHandler()                        */
1103
/************************************************************************/
1104

1105
/** Error handler that does not do anything, except for debug messages. */
1106
void CPL_STDCALL CPLQuietErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
35,677✔
1107
                                      const char *pszErrorMsg)
1108

1109
{
1110
    if (eErrClass == CE_Debug)
35,677✔
1111
        CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
3✔
1112
}
35,677✔
1113

1114
/************************************************************************/
1115
/*                    CPLQuietWarningsErrorHandler()                    */
1116
/************************************************************************/
1117

1118
/** Error handler that ignores CE_Warning messages. */
1119
void CPL_STDCALL CPLQuietWarningsErrorHandler(CPLErr eErrClass,
7✔
1120
                                              CPLErrorNum nError,
1121
                                              const char *pszErrorMsg)
1122

1123
{
1124
    if (eErrClass != CE_Warning)
7✔
1125
        CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
2✔
1126
}
7✔
1127

1128
/************************************************************************/
1129
/*                       CPLLoggingErrorHandler()                       */
1130
/************************************************************************/
1131

1132
/** Error handler that logs into the file defined by the CPL_LOG configuration
1133
 * option, or stderr otherwise.
1134
 */
1135
void CPL_STDCALL CPLLoggingErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
×
1136
                                        const char *pszErrorMsg)
1137

1138
{
1139
    if (!bLogInit)
×
1140
    {
1141
        bLogInit = true;
×
1142

1143
        CPLSetConfigOption("CPL_TIMESTAMP", "ON");
×
1144

1145
        const char *cpl_log = CPLGetConfigOption("CPL_LOG", nullptr);
×
1146

1147
        fpLog = stderr;
×
1148
        if (cpl_log != nullptr && EQUAL(cpl_log, "OFF"))
×
1149
        {
1150
            fpLog = nullptr;
×
1151
        }
1152
        else if (cpl_log != nullptr)
×
1153
        {
1154
            size_t nPathLen = strlen(cpl_log) + 20;
×
1155
            char *pszPath = static_cast<char *>(CPLMalloc(nPathLen));
×
1156
            strcpy(pszPath, cpl_log);
×
1157

1158
            int i = 0;
×
1159
            while ((fpLog = CPLfopenUTF8(pszPath, "rt")) != nullptr)
×
1160
            {
1161
                fclose(fpLog);
×
1162

1163
                // Generate sequenced log file names, inserting # before ext.
1164
                if (strrchr(cpl_log, '.') == nullptr)
×
1165
                {
1166
                    snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log, i++,
×
1167
                             ".log");
1168
                }
1169
                else
1170
                {
1171
                    size_t pos = 0;
×
1172
                    char *cpl_log_base = CPLStrdup(cpl_log);
×
1173
                    pos = strcspn(cpl_log_base, ".");
×
1174
                    if (pos > 0)
×
1175
                    {
1176
                        cpl_log_base[pos] = '\0';
×
1177
                    }
1178
                    snprintf(pszPath, nPathLen, "%s_%d%s", cpl_log_base, i++,
×
1179
                             ".log");
1180
                    CPLFree(cpl_log_base);
×
1181
                }
1182
            }
1183

1184
            fpLog = CPLfopenUTF8(pszPath, "wt");
×
1185
            CPLFree(pszPath);
×
1186
        }
1187
    }
1188

1189
    if (fpLog == nullptr)
×
1190
        return;
×
1191

1192
    if (eErrClass == CE_Debug)
×
1193
        fprintf(fpLog, "%s\n", pszErrorMsg);
×
1194
    else if (eErrClass == CE_Warning)
×
1195
        fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
×
1196
    else
1197
        fprintf(fpLog, "ERROR %d: %s\n", nError, pszErrorMsg);
×
1198

1199
    fflush(fpLog);
×
1200
}
1201

1202
/**********************************************************************
1203
 *                      CPLTurnFailureIntoWarning()                   *
1204
 **********************************************************************/
1205

1206
/** Whether failures should be turned into warnings.
1207
 */
1208
void CPLTurnFailureIntoWarning(int bOn)
12,194✔
1209
{
1210
    CPLErrorContext *psCtx = CPLGetErrorContext();
12,194✔
1211
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
12,194✔
1212
    {
1213
        fprintf(stderr, "CPLTurnFailureIntoWarning() failed.\n");
×
1214
        return;
×
1215
    }
1216
    psCtx->nFailureIntoWarning += (bOn) ? 1 : -1;
12,194✔
1217
    if (psCtx->nFailureIntoWarning < 0)
12,194✔
1218
    {
1219
        CPLDebug("CPL", "Wrong nesting of CPLTurnFailureIntoWarning(TRUE) / "
×
1220
                        "CPLTurnFailureIntoWarning(FALSE)");
1221
    }
1222
}
1223

1224
/**********************************************************************
1225
 *                          CPLSetErrorHandlerEx()                    *
1226
 **********************************************************************/
1227

1228
/**
1229
 * Install custom error handle with user's data. This method is
1230
 * essentially CPLSetErrorHandler with an added pointer to pUserData.
1231
 * The pUserData is not returned in the CPLErrorHandler, however, and
1232
 * must be fetched via CPLGetErrorHandlerUserData.
1233
 *
1234
 * @param pfnErrorHandlerNew new error handler function.
1235
 * @param pUserData User data to carry along with the error context.
1236
 * @return returns the previously installed error handler.
1237
 */
1238

1239
CPLErrorHandler CPL_STDCALL
1240
CPLSetErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew, void *pUserData)
19✔
1241
{
1242
    CPLErrorContext *psCtx = CPLGetErrorContext();
19✔
1243
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
19✔
1244
    {
1245
        fprintf(stderr, "CPLSetErrorHandlerEx() failed.\n");
×
1246
        return nullptr;
×
1247
    }
1248

1249
    if (psCtx->psHandlerStack != nullptr)
19✔
1250
    {
1251
        CPLDebug("CPL", "CPLSetErrorHandler() called with an error handler on "
×
1252
                        "the local stack.  New error handler will not be used "
1253
                        "immediately.");
1254
    }
1255

1256
    CPLErrorHandler pfnOldHandler = nullptr;
19✔
1257
    {
1258
        CPLMutexHolderD(&hErrorMutex);
19✔
1259

1260
        pfnOldHandler = pfnErrorHandler;
19✔
1261

1262
        pfnErrorHandler = pfnErrorHandlerNew;
19✔
1263

1264
        pErrorHandlerUserData = pUserData;
19✔
1265
    }
1266

1267
    return pfnOldHandler;
19✔
1268
}
1269

1270
/**********************************************************************
1271
 *                          CPLSetErrorHandler()                      *
1272
 **********************************************************************/
1273

1274
/**
1275
 * Install custom error handler.
1276
 *
1277
 * Allow the library's user to specify an error handler function.
1278
 * A valid error handler is a C function with the following prototype:
1279
 *
1280
 * \code{.cpp}
1281
 *     void MyErrorHandler(CPLErr eErrClass, int err_no, const char *msg)
1282
 * \endcode
1283
 *
1284
 * Pass NULL to come back to the default behavior.  The default behavior
1285
 * (CPLDefaultErrorHandler()) is to write the message to stderr.
1286
 *
1287
 * The msg will be a partially formatted error message not containing the
1288
 * "ERROR %d:" portion emitted by the default handler.  Message formatting
1289
 * is handled by CPLError() before calling the handler.  If the error
1290
 * handler function is passed a CE_Fatal class error and returns, then
1291
 * CPLError() will call abort(). Applications wanting to interrupt this
1292
 * fatal behavior will have to use longjmp(), or a C++ exception to
1293
 * indirectly exit the function.
1294
 *
1295
 * Another standard error handler is CPLQuietErrorHandler() which doesn't
1296
 * make any attempt to report the passed error or warning messages but
1297
 * will process debug messages via CPLDefaultErrorHandler.
1298
 *
1299
 * Note that error handlers set with CPLSetErrorHandler() apply to all
1300
 * threads in an application, while error handlers set with CPLPushErrorHandler
1301
 * are thread-local.  However, any error handlers pushed with
1302
 * CPLPushErrorHandler (and not removed with CPLPopErrorHandler) take
1303
 * precedence over the global error handlers set with CPLSetErrorHandler().
1304
 * Generally speaking CPLSetErrorHandler() would be used to set a desired
1305
 * global error handler, while CPLPushErrorHandler() would be used to install
1306
 * a temporary local error handler, such as CPLQuietErrorHandler() to suppress
1307
 * error reporting in a limited segment of code.
1308
 *
1309
 * @param pfnErrorHandlerNew new error handler function.
1310
 * @return returns the previously installed error handler.
1311
 */
1312
CPLErrorHandler CPL_STDCALL
1313
CPLSetErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
13✔
1314
{
1315
    return CPLSetErrorHandlerEx(pfnErrorHandlerNew, nullptr);
13✔
1316
}
1317

1318
/************************************************************************/
1319
/*                        CPLPushErrorHandler()                         */
1320
/************************************************************************/
1321

1322
/**
1323
 * Push a new CPLError handler.
1324
 *
1325
 * This pushes a new error handler on the thread-local error handler
1326
 * stack.  This handler will be used until removed with CPLPopErrorHandler().
1327
 *
1328
 * The CPLSetErrorHandler() docs have further information on how
1329
 * CPLError handlers work.
1330
 *
1331
 * @param pfnErrorHandlerNew new error handler function.
1332
 */
1333

1334
void CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
172,681✔
1335

1336
{
1337
    CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
172,681✔
1338
}
172,668✔
1339

1340
/************************************************************************/
1341
/*                        CPLPushErrorHandlerEx()                       */
1342
/************************************************************************/
1343

1344
/**
1345
 * Push a new CPLError handler with user data on the error context.
1346
 *
1347
 * This pushes a new error handler on the thread-local error handler
1348
 * stack.  This handler will be used until removed with CPLPopErrorHandler().
1349
 * Obtain the user data back by using CPLGetErrorContext().
1350
 *
1351
 * The CPLSetErrorHandler() docs have further information on how
1352
 * CPLError handlers work.
1353
 *
1354
 * @param pfnErrorHandlerNew new error handler function.
1355
 * @param pUserData User data to put on the error context.
1356
 */
1357
void CPL_STDCALL CPLPushErrorHandlerEx(CPLErrorHandler pfnErrorHandlerNew,
6,242,600✔
1358
                                       void *pUserData)
1359

1360
{
1361
    CPLErrorContext *psCtx = CPLGetErrorContext();
6,242,600✔
1362

1363
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
6,242,570✔
1364
    {
1365
        fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
19✔
1366
        return;
×
1367
    }
1368

1369
    CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
1370
        CPLMalloc(sizeof(CPLErrorHandlerNode)));
6,242,550✔
1371
    psNode->psNext = psCtx->psHandlerStack;
6,242,570✔
1372
    psNode->pfnHandler = pfnErrorHandlerNew;
6,242,570✔
1373
    psNode->pUserData = pUserData;
6,242,570✔
1374
    psNode->bCatchDebug = true;
6,242,570✔
1375
    psCtx->psHandlerStack = psNode;
6,242,570✔
1376
}
1377

1378
/************************************************************************/
1379
/*                         CPLPopErrorHandler()                         */
1380
/************************************************************************/
1381

1382
/**
1383
 * Pop error handler off stack.
1384
 *
1385
 * Discards the current error handler on the error handler stack, and restores
1386
 * the one in use before the last CPLPushErrorHandler() call.  This method
1387
 * has no effect if there are no error handlers on the current threads error
1388
 * handler stack.
1389
 */
1390

1391
void CPL_STDCALL CPLPopErrorHandler()
6,242,600✔
1392

1393
{
1394
    CPLErrorContext *psCtx = CPLGetErrorContext();
6,242,600✔
1395

1396
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
6,242,540✔
1397
    {
1398
        fprintf(stderr, "CPLPopErrorHandler() failed.\n");
18✔
1399
        return;
×
1400
    }
1401

1402
    if (psCtx->psHandlerStack != nullptr)
6,242,520✔
1403
    {
1404
        CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
6,242,530✔
1405

1406
        psCtx->psHandlerStack = psNode->psNext;
6,242,530✔
1407
        VSIFree(psNode);
6,242,530✔
1408
    }
1409
}
1410

1411
/************************************************************************/
1412
/*                         CPLCallPreviousHandler()                     */
1413
/************************************************************************/
1414

1415
/**
1416
 * Call the previously installed error handler in the error handler stack.
1417
 *
1418
 * Only to be used by a custom error handler that wants to forward events to
1419
 * the previous error handler.
1420
 *
1421
 * @since GDAL 3.8
1422
 */
1423

1424
void CPLCallPreviousHandler(CPLErr eErrClass, CPLErrorNum err_no,
19,814✔
1425
                            const char *pszMsg)
1426
{
1427
    CPLErrorContext *psCtx = CPLGetErrorContext();
19,814✔
1428

1429
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
19,814✔
1430
    {
1431
        fprintf(stderr, "CPLCallPreviousHandler() failed.\n");
×
1432
        return;
×
1433
    }
1434

1435
    if (psCtx->psHandlerStack != nullptr)
19,814✔
1436
    {
1437
        CPLErrorHandlerNode *psCurNode = psCtx->psHandlerStack;
19,814✔
1438
        psCtx->psHandlerStack = psCurNode->psNext;
19,814✔
1439
        if (psCtx->psHandlerStack)
19,814✔
1440
        {
1441
            CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
751✔
1442
            psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMsg);
751✔
1443
            if (psNewCurNode != psCtx->psHandlerStack)
751✔
1444
            {
1445
                fprintf(stderr, "CPLCallPreviousHandler() has detected that a "
×
1446
                                "previous error handler messed up with the "
1447
                                "error stack. Chaos guaranteed!\n");
1448
            }
1449
        }
1450
        else
1451
            CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
19,063✔
1452
        psCtx->psHandlerStack = psCurNode;
19,814✔
1453
    }
1454
    else
1455
    {
1456
        CPLDefaultErrorHandler(eErrClass, err_no, pszMsg);
×
1457
    }
1458
}
1459

1460
/************************************************************************/
1461
/*                 CPLSetCurrentErrorHandlerCatchDebug()                */
1462
/************************************************************************/
1463

1464
/**
1465
 * Set if the current error handler should intercept debug messages, or if
1466
 * they should be processed by the previous handler.
1467
 *
1468
 * By default when installing a custom error handler, this one intercepts
1469
 * debug messages. In some cases, this might not be desirable and the user
1470
 * would prefer that the previous installed handler (or the default one if no
1471
 * previous installed handler exists in the stack) deal with it. In which
1472
 * case, this function should be called with bCatchDebug = FALSE.
1473
 *
1474
 * @param bCatchDebug FALSE if the current error handler should not intercept
1475
 * debug messages
1476
 * @since GDAL 2.1
1477
 */
1478

1479
void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)
25,790✔
1480
{
1481
    CPLErrorContext *psCtx = CPLGetErrorContext();
25,790✔
1482

1483
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
25,777✔
1484
    {
1485
        fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
8✔
1486
        return;
×
1487
    }
1488

1489
    if (psCtx->psHandlerStack != nullptr)
25,769✔
1490
        psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
25,771✔
1491
    else
1492
        gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
×
1493
}
1494

1495
/************************************************************************/
1496
/*                             _CPLAssert()                             */
1497
/*                                                                      */
1498
/*      This function is called only when an assertion fails.           */
1499
/************************************************************************/
1500

1501
/**
1502
 * Report failure of a logical assertion.
1503
 *
1504
 * Applications would normally use the CPLAssert() macro which expands
1505
 * into code calling _CPLAssert() only if the condition fails.  _CPLAssert()
1506
 * will generate a CE_Fatal error call to CPLError(), indicating the file
1507
 * name, and line number of the failed assertion, as well as containing
1508
 * the assertion itself.
1509
 *
1510
 * There is no reason for application code to call _CPLAssert() directly.
1511
 */
1512

1513
void CPL_STDCALL _CPLAssert(const char *pszExpression, const char *pszFile,
×
1514
                            int iLine)
1515

1516
{
1517
    CPLError(CE_Fatal, CPLE_AssertionFailed,
×
1518
             "Assertion `%s' failed "
1519
             "in file `%s', line %d",
1520
             pszExpression, pszFile, iLine);
1521

1522
    // Just to please compiler so it is aware the function does not return.
1523
    abort();
×
1524
}
1525

1526
/************************************************************************/
1527
/*                       CPLCleanupErrorMutex()                         */
1528
/************************************************************************/
1529

1530
void CPLCleanupErrorMutex()
1,541✔
1531
{
1532
    if (hErrorMutex != nullptr)
1,541✔
1533
    {
1534
        CPLDestroyMutex(hErrorMutex);
175✔
1535
        hErrorMutex = nullptr;
175✔
1536
    }
1537
    if (fpLog != nullptr && fpLog != stderr)
1,541✔
1538
    {
1539
        fclose(fpLog);
1✔
1540
        fpLog = nullptr;
1✔
1541
        bLogInit = false;
1✔
1542
    }
1543
}
1,541✔
1544

1545
bool CPLIsDefaultErrorHandlerAndCatchDebug()
5,631✔
1546
{
1547
    CPLErrorContext *psCtx = CPLGetErrorContext();
5,631✔
1548
    return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
5,631✔
1549
           gbCatchDebug && pfnErrorHandler == CPLDefaultErrorHandler;
11,262✔
1550
}
1551

1552
/************************************************************************/
1553
/*               CPLErrorStateBackuper::CPLErrorStateBackuper()         */
1554
/************************************************************************/
1555

1556
CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
114,870✔
1557
    : m_nLastErrorNum(CPLGetLastErrorNo()),
114,870✔
1558
      m_nLastErrorType(CPLGetLastErrorType()),
229,692✔
1559
      m_osLastErrorMsg(CPLGetLastErrorMsg()),
1560
      m_nLastErrorCounter(CPLGetErrorCounter()),
229,710✔
1561
      m_poErrorHandlerPusher(
1562
          hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
1563
                   : nullptr)
114,849✔
1564
{
1565
}
114,843✔
1566

1567
/************************************************************************/
1568
/*               CPLErrorStateBackuper::~CPLErrorStateBackuper()        */
1569
/************************************************************************/
1570

1571
CPLErrorStateBackuper::~CPLErrorStateBackuper()
114,833✔
1572
{
1573
    CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
114,856✔
1574
                     m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
114,854✔
1575
}
114,843✔
1576

1577
/*! @cond Doxygen_Suppress */
1578

1579
/************************************************************************/
1580
/*                CPLErrorAccumulator::Context::~Context()              */
1581
/************************************************************************/
1582

1583
CPLErrorAccumulator::Context::~Context()
88,516✔
1584
{
1585
    CPLPopErrorHandler();
88,516✔
1586
}
88,520✔
1587

1588
/************************************************************************/
1589
/*             CPLErrorAccumulator::InstallForCurrentScope()            */
1590
/************************************************************************/
1591

1592
CPLErrorAccumulator::Context CPLErrorAccumulator::InstallForCurrentScope()
88,534✔
1593
{
1594
    CPLPushErrorHandlerEx(CPLErrorAccumulator::Accumulator, this);
88,534✔
1595
    return CPLErrorAccumulator::Context();
88,514✔
1596
}
1597

1598
/************************************************************************/
1599
/*                    CPLErrorAccumulator::ReplayErrors()               */
1600
/************************************************************************/
1601

1602
void CPLErrorAccumulator::ReplayErrors()
324✔
1603
{
1604
    std::lock_guard oLock(mutex);
648✔
1605
    for (const auto &err : errors)
329✔
1606
    {
1607
        CPLError(err.type, err.no, "%s", err.msg.c_str());
5✔
1608
    }
1609
}
324✔
1610

1611
/************************************************************************/
1612
/*                 CPLErrorAccumulator::Accumulator()                   */
1613
/************************************************************************/
1614

1615
/* static */ void CPL_STDCALL CPLErrorAccumulator::Accumulator(CPLErr eErr,
344✔
1616
                                                               CPLErrorNum no,
1617
                                                               const char *msg)
1618
{
1619
    if (eErr != CE_Debug)
344✔
1620
    {
1621
        CPLErrorAccumulator *pThis =
1622
            static_cast<CPLErrorAccumulator *>(CPLGetErrorHandlerUserData());
344✔
1623
        std::lock_guard oLock(pThis->mutex);
344✔
1624
        pThis->errors.push_back(
344✔
1625
            CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
688✔
1626
    }
1627
}
344✔
1628

1629
/*! @endcond */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc