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

OSGeo / gdal / 8872387746

29 Apr 2024 02:16AM UTC coverage: 69.076% (+0.003%) from 69.073%
8872387746

Pull #9801

github

web-flow
Bump actions/upload-artifact from 4.3.2 to 4.3.3

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.2 to 4.3.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/1746f4ab6...65462800f)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Pull Request #9801: Bump actions/upload-artifact from 4.3.2 to 4.3.3

534153 of 773282 relevant lines covered (69.08%)

205719.18 hits per line

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

67.05
/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
 * Permission is hereby granted, free of charge, to any person obtaining a
14
 * copy of this software and associated documentation files (the "Software"),
15
 * to deal in the Software without restriction, including without limitation
16
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17
 * and/or sell copies of the Software, and to permit persons to whom the
18
 * Software is furnished to do so, subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included
21
 * in all copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
26
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29
 * DEALINGS IN THE SOFTWARE.
30
 ****************************************************************************/
31

32
#include "cpl_error.h"
33

34
#ifndef _WIN32
35
#include <unistd.h>  // isatty()
36
#endif
37

38
#include <cstdarg>
39
#include <cstdio>
40
#include <cstdlib>
41
#include <cstring>
42

43
#include <algorithm>
44

45
#include "cpl_config.h"
46
#include "cpl_conv.h"
47
#include "cpl_multiproc.h"
48
#include "cpl_string.h"
49
#include "cpl_vsi.h"
50
#include "cpl_error_internal.h"
51

52
#if !defined(va_copy) && defined(__va_copy)
53
#define va_copy __va_copy
54
#endif
55

56
#define TIMESTAMP_DEBUG
57
// #define MEMORY_DEBUG
58

59
static CPLMutex *hErrorMutex = nullptr;
60
static void *pErrorHandlerUserData = nullptr;
61
static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
62
static bool gbCatchDebug = true;
63

64
constexpr int DEFAULT_LAST_ERR_MSG_SIZE =
65
#if !defined(HAVE_VSNPRINTF)
66
    20000
67
#else
68
    500
69
#endif
70
    ;
71

72
typedef struct errHandler
73
{
74
    struct errHandler *psNext;
75
    void *pUserData;
76
    CPLErrorHandler pfnHandler;
77
    bool bCatchDebug;
78
} CPLErrorHandlerNode;
79

80
typedef struct
81
{
82
    CPLErrorNum nLastErrNo;
83
    CPLErr eLastErrType;
84
    CPLErrorHandlerNode *psHandlerStack;
85
    int nLastErrMsgMax;
86
    int nFailureIntoWarning;
87
    bool bProgressMode;
88
    bool bEmitNewlineBeforeNextDbgMsg;
89
    GUInt32 nErrorCounter;
90
    char szLastErrMsg[DEFAULT_LAST_ERR_MSG_SIZE];
91
    // Do not add anything here. szLastErrMsg must be the last field.
92
    // See CPLRealloc() below.
93
} CPLErrorContext;
94

95
constexpr CPLErrorContext sNoErrorContext = {0,     CE_None, nullptr, 0, 0,
96
                                             false, false,   0,       ""};
97

98
constexpr CPLErrorContext sWarningContext = {
99
    0, CE_Warning, nullptr, 0, 0, false, false, 0, "A warning was emitted"};
100

101
constexpr CPLErrorContext sFailureContext = {
102
    0, CE_Warning, nullptr, 0, 0, false, false, 0, "A failure was emitted"};
103

104
#define IS_PREFEFINED_ERROR_CTX(psCtxt)                                        \
105
    (psCtx == &sNoErrorContext || psCtx == &sWarningContext ||                 \
106
     psCtxt == &sFailureContext)
107

108
/************************************************************************/
109
/*                     CPLErrorContextGetString()                       */
110
/************************************************************************/
111

112
// Makes clang -fsanitize=undefined happy since it doesn't like
113
// dereferencing szLastErrMsg[i>=DEFAULT_LAST_ERR_MSG_SIZE]
114

115
static char *CPLErrorContextGetString(CPLErrorContext *psCtxt)
549,274✔
116
{
117
    return psCtxt->szLastErrMsg;
549,274✔
118
}
119

120
/************************************************************************/
121
/*                         CPLGetErrorContext()                         */
122
/************************************************************************/
123

124
static CPLErrorContext *CPLGetErrorContext()
36,742,400✔
125

126
{
127
    int bError = FALSE;
36,742,400✔
128
    CPLErrorContext *psCtx = reinterpret_cast<CPLErrorContext *>(
129
        CPLGetTLSEx(CTLS_ERRORCONTEXT, &bError));
36,742,400✔
130
    if (bError)
36,741,200✔
131
        return nullptr;
×
132

133
    if (psCtx == nullptr)
36,741,200✔
134
    {
135
        psCtx = static_cast<CPLErrorContext *>(
136
            VSICalloc(sizeof(CPLErrorContext), 1));
1,643✔
137
        if (psCtx == nullptr)
1,645✔
138
        {
139
            fprintf(stderr, "Out of memory attempting to report error.\n");
×
140
            return nullptr;
×
141
        }
142
        psCtx->eLastErrType = CE_None;
1,645✔
143
        psCtx->nLastErrMsgMax = sizeof(psCtx->szLastErrMsg);
1,645✔
144
        CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
1,645✔
145
    }
146

147
    return psCtx;
36,741,600✔
148
}
149

150
/************************************************************************/
151
/*                         CPLGetErrorHandlerUserData()                 */
152
/************************************************************************/
153

154
/**
155
 * Fetch the user data for the error context
156
 *
157
 * Fetches the user data for the current error context.  You can
158
 * set the user data for the error context when you add your handler by
159
 * issuing CPLSetErrorHandlerEx() and CPLPushErrorHandlerEx().  Note that
160
 * user data is primarily intended for providing context within error handlers
161
 * themselves, but they could potentially be abused in other useful ways with
162
 * the usual caveat emptor understanding.
163
 *
164
 * @return the user data pointer for the error context
165
 */
166

167
void *CPL_STDCALL CPLGetErrorHandlerUserData(void)
3,974,060✔
168
{
169
    // get the current threadlocal or global error context user data
170
    CPLErrorContext *psCtx = CPLGetErrorContext();
3,974,060✔
171
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
3,974,060✔
172
        abort();
×
173
    return reinterpret_cast<void *>(psCtx->psHandlerStack
3,974,060✔
174
                                        ? psCtx->psHandlerStack->pUserData
3,974,060✔
175
                                        : pErrorHandlerUserData);
3,974,060✔
176
}
177

178
/************************************************************************/
179
/*                         CPLGetErrorHandler()                         */
180
/************************************************************************/
181

182
/**
183
 * Fetch the current error handler for the current error context.
184
 *
185
 * This will be the last error handler pushed in the thread-local error stack
186
 * with CPLPushErrorHandler()/CPLPushErrorHandlerEx(), or if the stack is
187
 * empty, the global error handler set with
188
 * CPLSetErrorHandler()/CPLSetErrorHandlerEx(), or the default global error
189
 * handler.
190
 *
191
 * @param[out] ppUserData Pointer to store the user data pointer. May be NULL
192
 * @since GDAL 3.7
193
 */
194

195
CPLErrorHandler CPLGetErrorHandler(void **ppUserData)
×
196
{
197
    CPLErrorContext *psCtx = CPLGetErrorContext();
×
198

199
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
×
200
    {
201
        fprintf(stderr, "CPLGetErrorHandler() failed.\n");
×
202
        if (ppUserData)
×
203
            *ppUserData = nullptr;
×
204
        return CPLDefaultErrorHandler;
×
205
    }
206

207
    if (psCtx->psHandlerStack != nullptr)
×
208
    {
209
        if (ppUserData)
×
210
            *ppUserData = psCtx->psHandlerStack->pUserData;
×
211
        return psCtx->psHandlerStack->pfnHandler;
×
212
    }
213

214
    CPLMutexHolderD(&hErrorMutex);
×
215
    if (ppUserData)
×
216
        *ppUserData = pErrorHandlerUserData;
×
217
    return pfnErrorHandler;
×
218
}
219

220
/************************************************************************/
221
/*                          ApplyErrorHandler()                         */
222
/************************************************************************/
223

224
static void ApplyErrorHandler(CPLErrorContext *psCtx, CPLErr eErrClass,
97,325✔
225
                              CPLErrorNum err_no, const char *pszMessage)
226
{
227
    bool bProcessed = false;
97,325✔
228

229
    if (psCtx->psHandlerStack != nullptr)
97,325✔
230
    {
231
        // iterate through the threadlocal handler stack
232
        if ((eErrClass != CE_Debug) || psCtx->psHandlerStack->bCatchDebug)
57,960✔
233
        {
234
            // call the error handler
235
            CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
57,946✔
236
            psCtx->psHandlerStack->pfnHandler(eErrClass, err_no, pszMessage);
57,946✔
237
            if (psNewCurNode != psCtx->psHandlerStack)
57,946✔
238
            {
239
                fprintf(stderr, "ApplyErrorHandler() has detected that a "
×
240
                                "previous error handler messed up with the "
241
                                "error stack. Chaos guaranteed!\n");
242
            }
243
            bProcessed = true;
57,946✔
244
        }
245
        else
246
        {
247
            // need to iterate to a parent handler for debug messages
248
            CPLErrorHandlerNode *psNode = psCtx->psHandlerStack->psNext;
14✔
249
            while (psNode != nullptr)
14✔
250
            {
251
                if (psNode->bCatchDebug)
13✔
252
                {
253
                    CPLErrorHandlerNode *psBackupCurNode =
13✔
254
                        psCtx->psHandlerStack;
255
                    psCtx->psHandlerStack = psNode;
13✔
256
                    CPLErrorHandlerNode *psNewCurNode = psCtx->psHandlerStack;
13✔
257
                    psNode->pfnHandler(eErrClass, err_no, pszMessage);
13✔
258
                    // cppcheck-suppress knownConditionTrueFalse
259
                    if (psNewCurNode != psCtx->psHandlerStack)
13✔
260
                    {
261
                        fprintf(stderr,
×
262
                                "ApplyErrorHandler() has detected that a "
263
                                "previous error handler messed up with the "
264
                                "error stack. Chaos guaranteed!\n");
265
                    }
266
                    psCtx->psHandlerStack = psBackupCurNode;
13✔
267
                    bProcessed = true;
13✔
268
                    break;
13✔
269
                }
270
                psNode = psNode->psNext;
×
271
            }
272
        }
273
    }
274

275
    if (!bProcessed)
97,325✔
276
    {
277
        // hit the global error handler
278
        CPLMutexHolderD(&hErrorMutex);
78,732✔
279
        if ((eErrClass != CE_Debug) || gbCatchDebug)
39,366✔
280
        {
281
            if (pfnErrorHandler != nullptr)
39,364✔
282
            {
283
                pfnErrorHandler(eErrClass, err_no, pszMessage);
39,362✔
284
            }
285
        }
286
        else /* if( eErrClass == CE_Debug ) */
287
        {
288
            // for CPLDebug messages we propagate to the default error handler
289
            CPLDefaultErrorHandler(eErrClass, err_no, pszMessage);
2✔
290
        }
291
    }
292
}
97,325✔
293

294
/**********************************************************************
295
 *                          CPLError()
296
 **********************************************************************/
297

298
/**
299
 * Report an error.
300
 *
301
 * This function reports an error in a manner that can be hooked
302
 * and reported appropriate by different applications.
303
 *
304
 * The effect of this function can be altered by applications by installing
305
 * a custom error handling using CPLSetErrorHandler().
306
 *
307
 * The eErrClass argument can have the value CE_Warning indicating that the
308
 * message is an informational warning, CE_Failure indicating that the
309
 * action failed, but that normal recover mechanisms will be used or
310
 * CE_Fatal meaning that a fatal error has occurred, and that CPLError()
311
 * should not return.
312
 *
313
 * The default behavior of CPLError() is to report errors to stderr,
314
 * and to abort() after reporting a CE_Fatal error.  It is expected that
315
 * some applications will want to suppress error reporting, and will want to
316
 * install a C++ exception, or longjmp() approach to no local fatal error
317
 * recovery.
318
 *
319
 * Regardless of how application error handlers or the default error
320
 * handler choose to handle an error, the error number, and message will
321
 * be stored for recovery with CPLGetLastErrorNo() and CPLGetLastErrorMsg().
322
 *
323
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
324
 * @param err_no the error number (CPLE_*) from cpl_error.h.
325
 * @param fmt a printf() style format string.  Any additional arguments
326
 * will be treated as arguments to fill in this format in a manner
327
 * similar to printf().
328
 */
329

330
void CPLError(CPLErr eErrClass, CPLErrorNum err_no,
95,796✔
331
              CPL_FORMAT_STRING(const char *fmt), ...)
332
{
333
    va_list args;
334

335
    // Expand the error message.
336
    va_start(args, fmt);
95,796✔
337
    CPLErrorV(eErrClass, err_no, fmt, args);
95,796✔
338
    va_end(args);
95,796✔
339
}
95,796✔
340

341
/************************************************************************/
342
/*                             CPLErrorV()                              */
343
/************************************************************************/
344

345
/** Same as CPLError() but with a va_list */
346
void CPLErrorV(CPLErr eErrClass, CPLErrorNum err_no, const char *fmt,
96,666✔
347
               va_list args)
348
{
349
    CPLErrorContext *psCtx = CPLGetErrorContext();
96,666✔
350
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
96,670✔
351
    {
352
        int bMemoryError = FALSE;
8✔
353
        if (eErrClass == CE_Warning)
8✔
354
        {
355
            CPLSetTLSWithFreeFuncEx(
×
356
                CTLS_ERRORCONTEXT,
357
                reinterpret_cast<void *>(
358
                    const_cast<CPLErrorContext *>(&sWarningContext)),
359
                nullptr, &bMemoryError);
360
        }
361
        else if (eErrClass == CE_Failure)
8✔
362
        {
363
            CPLSetTLSWithFreeFuncEx(
×
364
                CTLS_ERRORCONTEXT,
365
                reinterpret_cast<void *>(
366
                    const_cast<CPLErrorContext *>(&sFailureContext)),
367
                nullptr, &bMemoryError);
368
        }
369

370
        // TODO: Is it possible to move the entire szShortMessage under the if
371
        // pfnErrorHandler?
372
        char szShortMessage[80] = {};
8✔
373
        CPLvsnprintf(szShortMessage, sizeof(szShortMessage), fmt, args);
8✔
374

375
        CPLMutexHolderD(&hErrorMutex);
×
376
        if (pfnErrorHandler != nullptr)
×
377
            pfnErrorHandler(eErrClass, err_no, szShortMessage);
×
378
        return;
×
379
    }
380

381
    if (psCtx->nFailureIntoWarning > 0 && eErrClass == CE_Failure)
96,662✔
382
        eErrClass = CE_Warning;
2✔
383

384
/* -------------------------------------------------------------------- */
385
/*      Expand the error message                                        */
386
/* -------------------------------------------------------------------- */
387
#if defined(HAVE_VSNPRINTF)
388
    {
389
        va_list wrk_args;
390

391
#ifdef va_copy
392
        va_copy(wrk_args, args);
96,662✔
393
#else
394
        wrk_args = args;
395
#endif
396

397
        /* --------------------------------------------------------------------
398
         */
399
        /*      If CPL_ACCUM_ERROR_MSG=ON accumulate the error messages, */
400
        /*      rather than just replacing the last error message. */
401
        /* --------------------------------------------------------------------
402
         */
403
        int nPreviousSize = 0;
96,662✔
404
        if (psCtx->psHandlerStack != nullptr &&
154,574✔
405
            EQUAL(CPLGetConfigOption("CPL_ACCUM_ERROR_MSG", ""), "ON"))
57,903✔
406
        {
407
            nPreviousSize = static_cast<int>(strlen(psCtx->szLastErrMsg));
×
408
            if (nPreviousSize)
×
409
            {
410
                if (nPreviousSize + 1 + 1 >= psCtx->nLastErrMsgMax)
×
411
                {
412
                    psCtx->nLastErrMsgMax *= 3;
×
413
                    psCtx = static_cast<CPLErrorContext *>(
414
                        CPLRealloc(psCtx, sizeof(CPLErrorContext) -
×
415
                                              DEFAULT_LAST_ERR_MSG_SIZE +
416
                                              psCtx->nLastErrMsgMax + 1));
×
417
                    CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
×
418
                }
419
                char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
×
420
                pszLastErrMsg[nPreviousSize] = '\n';
×
421
                pszLastErrMsg[nPreviousSize + 1] = '\0';
×
422
                nPreviousSize++;
×
423
            }
424
        }
425

426
        int nPR = 0;
96,671✔
427
        while (((nPR = CPLvsnprintf(psCtx->szLastErrMsg + nPreviousSize,
13✔
428
                                    psCtx->nLastErrMsgMax - nPreviousSize, fmt,
96,684✔
429
                                    wrk_args)) == -1 ||
96,671✔
430
                nPR >= psCtx->nLastErrMsgMax - nPreviousSize - 1) &&
96,702✔
431
               psCtx->nLastErrMsgMax < 1000000)
22✔
432
        {
433
#ifdef va_copy
434
            va_end(wrk_args);
13✔
435
            va_copy(wrk_args, args);
13✔
436
#else
437
            wrk_args = args;
438
#endif
439
            psCtx->nLastErrMsgMax *= 3;
13✔
440
            psCtx = static_cast<CPLErrorContext *>(CPLRealloc(
26✔
441
                psCtx, sizeof(CPLErrorContext) - DEFAULT_LAST_ERR_MSG_SIZE +
442
                           psCtx->nLastErrMsgMax + 1));
13✔
443
            CPLSetTLS(CTLS_ERRORCONTEXT, psCtx, TRUE);
13✔
444
        }
445

446
        va_end(wrk_args);
96,667✔
447
    }
448
#else
449
    // !HAVE_VSNPRINTF
450
    CPLvsnprintf(psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
451
#endif
452

453
    /* -------------------------------------------------------------------- */
454
    /*      Obfuscate any password in error message                         */
455
    /* -------------------------------------------------------------------- */
456
    char *pszPassword = strstr(psCtx->szLastErrMsg, "password=");
96,667✔
457
    if (pszPassword != nullptr)
96,667✔
458
    {
459
        char *pszIter = pszPassword + strlen("password=");
×
460
        while (*pszIter != ' ' && *pszIter != '\0')
×
461
        {
462
            *pszIter = 'X';
×
463
            pszIter++;
×
464
        }
465
    }
466

467
    /* -------------------------------------------------------------------- */
468
    /*      If the user provided an handling function, then                 */
469
    /*      call it, otherwise print the error to stderr and return.        */
470
    /* -------------------------------------------------------------------- */
471
    psCtx->nLastErrNo = err_no;
96,667✔
472
    psCtx->eLastErrType = eErrClass;
96,667✔
473
    if (psCtx->nErrorCounter == ~(0U))
96,667✔
474
        psCtx->nErrorCounter = 0;
×
475
    else
476
        psCtx->nErrorCounter++;
96,667✔
477

478
    if (CPLGetConfigOption("CPL_LOG_ERRORS", nullptr) != nullptr)
96,667✔
479
        CPLDebug("CPLError", "%s", psCtx->szLastErrMsg);
×
480

481
    /* -------------------------------------------------------------------- */
482
    /*      Invoke the current error handler.                               */
483
    /* -------------------------------------------------------------------- */
484
    ApplyErrorHandler(psCtx, eErrClass, err_no, psCtx->szLastErrMsg);
96,672✔
485

486
    if (eErrClass == CE_Fatal)
96,672✔
487
        abort();
×
488
}
489

490
/************************************************************************/
491
/*                         CPLEmergencyError()                          */
492
/************************************************************************/
493

494
/**
495
 * Fatal error when things are bad.
496
 *
497
 * This function should be called in an emergency situation where
498
 * it is unlikely that a regular error report would work.  This would
499
 * include in the case of heap exhaustion for even small allocations,
500
 * or any failure in the process of reporting an error (such as TLS
501
 * allocations).
502
 *
503
 * This function should never return.  After the error message has been
504
 * reported as best possible, the application will abort() similarly to how
505
 * CPLError() aborts on CE_Fatal class errors.
506
 *
507
 * @param pszMessage the error message to report.
508
 */
509

510
void CPLEmergencyError(const char *pszMessage)
×
511
{
512
    static bool bInEmergencyError = false;
513

514
    // If we are already in emergency error then one of the
515
    // following failed, so avoid them the second time through.
516
    if (!bInEmergencyError)
×
517
    {
518
        bInEmergencyError = true;
×
519
        CPLErrorContext *psCtx =
520
            static_cast<CPLErrorContext *>(CPLGetTLS(CTLS_ERRORCONTEXT));
×
521

522
        ApplyErrorHandler(psCtx, CE_Fatal, CPLE_AppDefined, pszMessage);
×
523
    }
524

525
    // Ultimate fallback.
526
    fprintf(stderr, "FATAL: %s\n", pszMessage);
×
527

528
    abort();
×
529
}
530

531
/************************************************************************/
532
/*                    CPLGetProcessMemorySize()                         */
533
/************************************************************************/
534

535
#ifdef MEMORY_DEBUG
536

537
#ifdef __linux
538
static int CPLGetProcessMemorySize()
539
{
540
    FILE *fp = fopen("/proc/self/status", "r");
541
    if (fp == nullptr)
542
        return -1;
543
    int nRet = -1;
544
    char szLine[128] = {};
545
    while (fgets(szLine, sizeof(szLine), fp) != nullptr)
546
    {
547
        if (STARTS_WITH(szLine, "VmSize:"))
548
        {
549
            const char *pszPtr = szLine;
550
            while (!(*pszPtr == '\0' || (*pszPtr >= '0' && *pszPtr <= '9')))
551
                pszPtr++;
552
            nRet = atoi(pszPtr);
553
            break;
554
        }
555
    }
556
    fclose(fp);
557
    return nRet;
558
}
559
#else
560
#error CPLGetProcessMemorySize() unimplemented for this OS
561
#endif
562

563
#endif  // def MEMORY_DEBUG
564

565
/************************************************************************/
566
/*                        CPLGettimeofday()                             */
567
/************************************************************************/
568

569
#if defined(_WIN32) && !defined(__CYGWIN__)
570
#include <sys/timeb.h>
571

572
namespace
573
{
574
struct CPLTimeVal
575
{
576
    time_t tv_sec; /* seconds */
577
    long tv_usec;  /* and microseconds */
578
};
579
}  // namespace
580

581
static int CPLGettimeofday(struct CPLTimeVal *tp, void * /* timezonep*/)
582
{
583
    struct _timeb theTime;
584

585
    _ftime(&theTime);
586
    tp->tv_sec = static_cast<time_t>(theTime.time);
587
    tp->tv_usec = theTime.millitm * 1000;
588
    return 0;
589
}
590
#else
591
#include <sys/time.h> /* for gettimeofday() */
592
#define CPLTimeVal timeval
593
#define CPLGettimeofday(t, u) gettimeofday(t, u)
594
#endif
595

596
#ifndef WITHOUT_CPLDEBUG
597

598
/************************************************************************/
599
/*                             CPLvDebug()                              */
600
/************************************************************************/
601

602
static void CPLvDebug(const char *pszCategory,
593,652✔
603
                      CPL_FORMAT_STRING(const char *pszFormat), va_list args)
604
{
605
    CPLErrorContext *psCtx = CPLGetErrorContext();
593,652✔
606
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
593,642✔
607
        return;
5✔
608
    const char *pszDebug = CPLGetConfigOption("CPL_DEBUG", nullptr);
593,637✔
609

610
    /* -------------------------------------------------------------------- */
611
    /*      Does this message pass our current criteria?                    */
612
    /* -------------------------------------------------------------------- */
613
    if (pszDebug == nullptr)
593,719✔
614
        return;
592,987✔
615

616
    if (!EQUAL(pszDebug, "ON") && !EQUAL(pszDebug, ""))
732✔
617
    {
618
        const size_t nLen = strlen(pszCategory);
120✔
619

620
        size_t i = 0;
120✔
621
        for (i = 0; pszDebug[i] != '\0'; i++)
826✔
622
        {
623
            if (EQUALN(pszCategory, pszDebug + i, nLen))
747✔
624
                break;
41✔
625
        }
626

627
        if (pszDebug[i] == '\0')
120✔
628
            return;
79✔
629
    }
630

631
    /* -------------------------------------------------------------------- */
632
    /*    Allocate a block for the error.                                   */
633
    /* -------------------------------------------------------------------- */
634
    const int ERROR_MAX = 25000;
653✔
635
    char *pszMessage = static_cast<char *>(VSIMalloc(ERROR_MAX));
653✔
636
    if (pszMessage == nullptr)
653✔
637
        return;
×
638

639
    /* -------------------------------------------------------------------- */
640
    /*      Dal -- always log a timestamp as the first part of the line     */
641
    /*      to ensure one is looking at what one should be looking at!      */
642
    /* -------------------------------------------------------------------- */
643

644
    pszMessage[0] = '\0';
653✔
645
#ifdef TIMESTAMP_DEBUG
646
    if (CPLGetConfigOption("CPL_TIMESTAMP", nullptr) != nullptr)
653✔
647
    {
648
        static struct CPLTimeVal tvStart;
649
        static const auto unused = CPLGettimeofday(&tvStart, nullptr);
×
650
        CPL_IGNORE_RET_VAL(unused);
×
651
        struct CPLTimeVal tv;
652
        CPLGettimeofday(&tv, nullptr);
×
653
        strcpy(pszMessage, "[");
×
654
        strcat(pszMessage, VSICTime(static_cast<unsigned long>(tv.tv_sec)));
×
655

656
        // On windows anyway, ctime puts a \n at the end, but I'm not
657
        // convinced this is standard behavior, so we'll get rid of it
658
        // carefully
659

660
        if (pszMessage[strlen(pszMessage) - 1] == '\n')
×
661
        {
662
            pszMessage[strlen(pszMessage) - 1] = 0;  // blow it out
×
663
        }
664
        CPLsnprintf(pszMessage + strlen(pszMessage),
×
665
                    ERROR_MAX - strlen(pszMessage),
×
666
                    "].%04d, %03.04f: ", static_cast<int>(tv.tv_usec / 100),
×
667
                    tv.tv_sec + tv.tv_usec * 1e-6 -
×
668
                        (tvStart.tv_sec + tvStart.tv_usec * 1e-6));
×
669
    }
670
#endif
671

672
/* -------------------------------------------------------------------- */
673
/*      Add the process memory size.                                    */
674
/* -------------------------------------------------------------------- */
675
#ifdef MEMORY_DEBUG
676
    char szVmSize[32] = {};
677
    CPLsprintf(szVmSize, "[VmSize: %d] ", CPLGetProcessMemorySize());
678
    strcat(pszMessage, szVmSize);
679
#endif
680

681
    /* -------------------------------------------------------------------- */
682
    /*      Add the category.                                               */
683
    /* -------------------------------------------------------------------- */
684
    strcat(pszMessage, pszCategory);
653✔
685
    strcat(pszMessage, ": ");
653✔
686

687
    /* -------------------------------------------------------------------- */
688
    /*      Format the application provided portion of the debug message.   */
689
    /* -------------------------------------------------------------------- */
690
    CPLvsnprintf(pszMessage + strlen(pszMessage),
653✔
691
                 ERROR_MAX - strlen(pszMessage), pszFormat, args);
653✔
692

693
    /* -------------------------------------------------------------------- */
694
    /*      Obfuscate any password in error message                         */
695
    /* -------------------------------------------------------------------- */
696

697
    char *pszPassword = strstr(pszMessage, "password=");
653✔
698
    if (pszPassword != nullptr)
653✔
699
    {
700
        char *pszIter = pszPassword + strlen("password=");
×
701
        while (*pszIter != ' ' && *pszIter != '\0')
×
702
        {
703
            *pszIter = 'X';
×
704
            pszIter++;
×
705
        }
706
    }
707

708
    /* -------------------------------------------------------------------- */
709
    /*      Invoke the current error handler.                               */
710
    /* -------------------------------------------------------------------- */
711
    ApplyErrorHandler(psCtx, CE_Debug, CPLE_None, pszMessage);
653✔
712

713
    VSIFree(pszMessage);
653✔
714
}
715

716
#endif  // !WITHOUT_CPLDEBUG
717

718
/************************************************************************/
719
/*                              CPLDebug()                              */
720
/************************************************************************/
721

722
/**
723
 * Display a debugging message.
724
 *
725
 * The category argument is used in conjunction with the CPL_DEBUG
726
 * environment variable to establish if the message should be displayed.
727
 * If the CPL_DEBUG environment variable is not set, no debug messages
728
 * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
729
 * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
730
 * debug messages are shown.  Otherwise only messages whose category appears
731
 * somewhere within the CPL_DEBUG value are displayed (as determined by
732
 * strstr()).
733
 *
734
 * Categories are usually an identifier for the subsystem producing the
735
 * error.  For instance "GDAL" might be used for the GDAL core, and "TIFF"
736
 * for messages from the TIFF translator.
737
 *
738
 * @param pszCategory name of the debugging message category.
739
 * @param pszFormat printf() style format string for message to display.
740
 *        Remaining arguments are assumed to be for format.
741
 */
742

743
#ifdef WITHOUT_CPLDEBUG
744
// Do not include CPLDebug.  Only available in custom builds.
745
#else
746

747
void CPLDebug(const char *pszCategory, CPL_FORMAT_STRING(const char *pszFormat),
593,694✔
748
              ...)
749

750
{
751
    va_list args;
752
    va_start(args, pszFormat);
593,694✔
753
    CPLvDebug(pszCategory, pszFormat, args);
593,694✔
754
    va_end(args);
593,717✔
755
}
593,717✔
756

757
#endif  // WITHOUT_CPLDEBUG
758

759
/************************************************************************/
760
/*                         CPLDebugProgress()                           */
761
/************************************************************************/
762

763
/**
764
 * Display a debugging message indicating a progression.
765
 *
766
 * This is the same as CPLDebug(), except that when displaying on the terminal,
767
 * it will erase the previous debug progress message. This is for example
768
 * appropriate to display increasing percentages for a task.
769
 *
770
 * The category argument is used in conjunction with the CPL_DEBUG
771
 * environment variable to establish if the message should be displayed.
772
 * If the CPL_DEBUG environment variable is not set, no debug messages
773
 * are emitted (use CPLError(CE_Warning, ...) to ensure messages are displayed).
774
 * If CPL_DEBUG is set, but is an empty string or the word "ON" then all
775
 * debug messages are shown.  Otherwise only messages whose category appears
776
 * somewhere within the CPL_DEBUG value are displayed (as determined by
777
 * strstr()).
778
 *
779
 * Categories are usually an identifier for the subsystem producing the
780
 * error.  For instance "GDAL" might be used for the GDAL core, and "TIFF"
781
 * for messages from the TIFF translator.
782
 *
783
 * @param pszCategory name of the debugging message category.
784
 * @param pszFormat printf() style format string for message to display.
785
 *        Remaining arguments are assumed to be for format.
786
 * @since 3.9
787
 */
788

789
#ifdef WITHOUT_CPLDEBUG
790
// Do not include CPLDebugProgress. Only available in custom builds.
791
#else
792
void CPLDebugProgress(const char *pszCategory,
2✔
793
                      CPL_FORMAT_STRING(const char *pszFormat), ...)
794

795
{
796
    CPLErrorContext *psCtx = CPLGetErrorContext();
2✔
797
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
2✔
798
        return;
×
799

800
    psCtx->bProgressMode = true;
2✔
801

802
    va_list args;
803
    va_start(args, pszFormat);
2✔
804
    CPLvDebug(pszCategory, pszFormat, args);
2✔
805
    va_end(args);
2✔
806

807
    psCtx->bProgressMode = false;
2✔
808
}
809
#endif  // !WITHOUT_CPLDEBUG
810

811
/**********************************************************************
812
 *                          CPLErrorReset()
813
 **********************************************************************/
814

815
/**
816
 * Erase any traces of previous errors.
817
 *
818
 * This is normally used to ensure that an error which has been recovered
819
 * from does not appear to be still in play with high level functions.
820
 */
821

822
void CPL_STDCALL CPLErrorReset()
4,689,520✔
823
{
824
    CPLErrorContext *psCtx = CPLGetErrorContext();
4,689,520✔
825
    if (psCtx == nullptr)
4,689,520✔
826
        return;
×
827
    if (IS_PREFEFINED_ERROR_CTX(psCtx))
4,689,520✔
828
    {
829
        int bMemoryError = FALSE;
×
830
        CPLSetTLSWithFreeFuncEx(
×
831
            CTLS_ERRORCONTEXT,
832
            reinterpret_cast<void *>(
833
                const_cast<CPLErrorContext *>(&sNoErrorContext)),
834
            nullptr, &bMemoryError);
835
        return;
×
836
    }
837

838
    psCtx->nLastErrNo = CPLE_None;
4,689,520✔
839
    psCtx->szLastErrMsg[0] = '\0';
4,689,520✔
840
    psCtx->eLastErrType = CE_None;
4,689,520✔
841
    psCtx->nErrorCounter = 0;
4,689,520✔
842
}
843

844
/**********************************************************************
845
 *                       CPLErrorSetState()
846
 **********************************************************************/
847

848
static void CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
549,290✔
849
                             const char *pszMsg, GUInt32 *pnErrorCounter)
850
{
851
    CPLErrorContext *psCtx = CPLGetErrorContext();
549,290✔
852
    if (psCtx == nullptr)
549,258✔
853
        return;
×
854
    if (IS_PREFEFINED_ERROR_CTX(psCtx))
549,258✔
855
    {
856
        int bMemoryError = FALSE;
37✔
857
        if (eErrClass == CE_None)
37✔
858
            CPLSetTLSWithFreeFuncEx(
×
859
                CTLS_ERRORCONTEXT,
860
                reinterpret_cast<void *>(
861
                    const_cast<CPLErrorContext *>(&sNoErrorContext)),
862
                nullptr, &bMemoryError);
863
        else if (eErrClass == CE_Warning)
37✔
864
            CPLSetTLSWithFreeFuncEx(
×
865
                CTLS_ERRORCONTEXT,
866
                reinterpret_cast<void *>(
867
                    const_cast<CPLErrorContext *>(&sWarningContext)),
868
                nullptr, &bMemoryError);
869
        else if (eErrClass == CE_Failure)
37✔
870
            CPLSetTLSWithFreeFuncEx(
×
871
                CTLS_ERRORCONTEXT,
872
                reinterpret_cast<void *>(
873
                    const_cast<CPLErrorContext *>(&sFailureContext)),
874
                nullptr, &bMemoryError);
875
        return;
×
876
    }
877

878
    psCtx->nLastErrNo = err_no;
549,221✔
879
    const size_t size = std::min(static_cast<size_t>(psCtx->nLastErrMsgMax - 1),
1,098,510✔
880
                                 strlen(pszMsg));
549,221✔
881
    char *pszLastErrMsg = CPLErrorContextGetString(psCtx);
549,285✔
882
    memcpy(pszLastErrMsg, pszMsg, size);
549,265✔
883
    pszLastErrMsg[size] = '\0';
549,265✔
884
    psCtx->eLastErrType = eErrClass;
549,265✔
885
    if (pnErrorCounter)
549,265✔
886
        psCtx->nErrorCounter = *pnErrorCounter;
73,918✔
887
}
888

889
/**
890
 * Restore an error state, without emitting an error.
891
 *
892
 * Can be useful if a routine might call CPLErrorReset() and one wants to
893
 * preserve the previous error state.
894
 *
895
 * @since GDAL 2.0
896
 */
897

898
void CPL_DLL CPLErrorSetState(CPLErr eErrClass, CPLErrorNum err_no,
475,368✔
899
                              const char *pszMsg)
900
{
901
    CPLErrorSetState(eErrClass, err_no, pszMsg, nullptr);
475,368✔
902
}
475,368✔
903

904
/**********************************************************************
905
 *                          CPLGetLastErrorNo()
906
 **********************************************************************/
907

908
/**
909
 * Fetch the last error number.
910
 *
911
 * Fetches the last error number posted with CPLError(), that hasn't
912
 * been cleared by CPLErrorReset().  This is the error number, not the error
913
 * class.
914
 *
915
 * @return the error number of the last error to occur, or CPLE_None (0)
916
 * if there are no posted errors.
917
 */
918

919
CPLErrorNum CPL_STDCALL CPLGetLastErrorNo()
775,337✔
920
{
921
    CPLErrorContext *psCtx = CPLGetErrorContext();
775,337✔
922
    if (psCtx == nullptr)
772,940✔
923
        return 0;
×
924

925
    return psCtx->nLastErrNo;
772,940✔
926
}
927

928
/**********************************************************************
929
 *                          CPLGetLastErrorType()
930
 **********************************************************************/
931

932
/**
933
 * Fetch the last error type.
934
 *
935
 * Fetches the last error type posted with CPLError(), that hasn't
936
 * been cleared by CPLErrorReset().  This is the error class, not the error
937
 * number.
938
 *
939
 * @return the error type of the last error to occur, or CE_None (0)
940
 * if there are no posted errors.
941
 */
942

943
CPLErr CPL_STDCALL CPLGetLastErrorType()
7,287,410✔
944
{
945
    CPLErrorContext *psCtx = CPLGetErrorContext();
7,287,410✔
946
    if (psCtx == nullptr)
7,287,400✔
947
        return CE_None;
×
948

949
    return psCtx->eLastErrType;
7,287,400✔
950
}
951

952
/**********************************************************************
953
 *                          CPLGetLastErrorMsg()
954
 **********************************************************************/
955

956
/**
957
 * Get the last error message.
958
 *
959
 * Fetches the last error message posted with CPLError(), that hasn't
960
 * been cleared by CPLErrorReset().  The returned pointer is to an internal
961
 * string that should not be altered or freed.
962
 *
963
 * @return the last error message, or an empty string ("") if there is no
964
 * posted error message.
965
 */
966

967
const char *CPL_STDCALL CPLGetLastErrorMsg()
310,487✔
968
{
969
    CPLErrorContext *psCtx = CPLGetErrorContext();
310,487✔
970
    if (psCtx == nullptr)
310,431✔
971
        return "";
×
972

973
    return psCtx->szLastErrMsg;
310,431✔
974
}
975

976
/**********************************************************************
977
 *                          CPLGetErrorCounter()
978
 **********************************************************************/
979

980
/**
981
 * Get the error counter
982
 *
983
 * Fetches the number of errors emitted in the current error context,
984
 * since the last call to CPLErrorReset()
985
 *
986
 * @return the error counter.
987
 * @since GDAL 2.3
988
 */
989

990
GUInt32 CPL_STDCALL CPLGetErrorCounter()
10,078,100✔
991
{
992
    CPLErrorContext *psCtx = CPLGetErrorContext();
10,078,100✔
993
    if (psCtx == nullptr)
10,078,100✔
994
        return 0;
×
995

996
    return psCtx->nErrorCounter;
10,078,100✔
997
}
998

999
/************************************************************************/
1000
/*                       CPLDefaultErrorHandler()                       */
1001
/************************************************************************/
1002

1003
static FILE *fpLog = stderr;
1004
static bool bLogInit = false;
1005

1006
static FILE *CPLfopenUTF8(const char *pszFilename, const char *pszAccess)
1✔
1007
{
1008
    FILE *f;
1009
#ifdef _WIN32
1010
    wchar_t *pwszFilename =
1011
        CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
1012
    wchar_t *pwszAccess =
1013
        CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
1014
    f = _wfopen(pwszFilename, pwszAccess);
1015
    VSIFree(pwszFilename);
1016
    VSIFree(pwszAccess);
1017
#else
1018
    f = fopen(pszFilename, pszAccess);
1✔
1019
#endif
1020
    return f;
1✔
1021
}
1022

1023
/** Default error handler. */
1024
void CPL_STDCALL CPLDefaultErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
58,310✔
1025
                                        const char *pszErrorMsg)
1026

1027
{
1028
    static int nCount = 0;
1029
    static int nMaxErrors = -1;
1030
    static const char *pszErrorSeparator = ":";
1031

1032
    if (eErrClass != CE_Debug)
58,310✔
1033
    {
1034
        if (nMaxErrors == -1)
57,704✔
1035
        {
1036
            nMaxErrors =
195✔
1037
                atoi(CPLGetConfigOption("CPL_MAX_ERROR_REPORTS", "1000"));
195✔
1038
            // If running GDAL as a CustomBuild Command os MSBuild, "ERROR bla:"
1039
            // is considered as failing the job. This is rarely the intended
1040
            // behavior
1041
            pszErrorSeparator = CPLGetConfigOption("CPL_ERROR_SEPARATOR", ":");
195✔
1042
        }
1043

1044
        nCount++;
57,704✔
1045
        if (nCount > nMaxErrors && nMaxErrors > 0)
57,704✔
1046
            return;
54,436✔
1047
    }
1048

1049
    if (!bLogInit)
3,874✔
1050
    {
1051
        bLogInit = true;
208✔
1052

1053
        fpLog = stderr;
208✔
1054
        const char *pszLog = CPLGetConfigOption("CPL_LOG", nullptr);
208✔
1055
        if (pszLog != nullptr)
208✔
1056
        {
1057
            const bool bAppend =
1058
                CPLGetConfigOption("CPL_LOG_APPEND", nullptr) != nullptr;
1✔
1059
            const char *pszAccess = bAppend ? "at" : "wt";
1✔
1060
            fpLog = CPLfopenUTF8(pszLog, pszAccess);
1✔
1061
            if (fpLog == nullptr)
1✔
1062
                fpLog = stderr;
×
1063
        }
1064
    }
1065

1066
    if (eErrClass == CE_Debug)
3,874✔
1067
    {
1068
#ifndef _WIN32
1069
        CPLErrorContext *psCtx = CPLGetErrorContext();
606✔
1070
        if (psCtx != nullptr && !IS_PREFEFINED_ERROR_CTX(psCtx) &&
606✔
1071
            fpLog == stderr && isatty(static_cast<int>(fileno(stderr))))
1,212✔
1072
        {
1073
            if (psCtx->bProgressMode)
×
1074
            {
1075
                // Erase the content of the current line
1076
                fprintf(stderr, "\r");
×
1077
                fprintf(stderr, "%s", pszErrorMsg);
×
1078
                fflush(stderr);
×
1079
                psCtx->bEmitNewlineBeforeNextDbgMsg = true;
×
1080
            }
1081
            else
1082
            {
1083
                if (psCtx->bEmitNewlineBeforeNextDbgMsg)
×
1084
                {
1085
                    psCtx->bEmitNewlineBeforeNextDbgMsg = false;
×
1086
                    fprintf(fpLog, "\n");
×
1087
                }
1088
                fprintf(fpLog, "%s\n", pszErrorMsg);
×
1089
            }
1090
        }
1091
        else
1092
#endif
1093
        {
1094
            fprintf(fpLog, "%s\n", pszErrorMsg);
606✔
1095
        }
1096
    }
1097
    else if (eErrClass == CE_Warning)
3,268✔
1098
        fprintf(fpLog, "Warning %d: %s\n", nError, pszErrorMsg);
2,505✔
1099
    else
1100
        fprintf(fpLog, "ERROR %d%s %s\n", nError, pszErrorSeparator,
763✔
1101
                pszErrorMsg);
1102

1103
    if (eErrClass != CE_Debug && nMaxErrors > 0 && nCount == nMaxErrors)
3,874✔
1104
    {
1105
        fprintf(fpLog,
2✔
1106
                "More than %d errors or warnings have been reported. "
1107
                "No more will be reported from now.\n",
1108
                nMaxErrors);
1109
    }
1110

1111
    fflush(fpLog);
3,874✔
1112
}
1113

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

1118
/** Error handler that does not do anything, except for debug messages. */
1119
void CPL_STDCALL CPLQuietErrorHandler(CPLErr eErrClass, CPLErrorNum nError,
36,663✔
1120
                                      const char *pszErrorMsg)
1121

1122
{
1123
    if (eErrClass == CE_Debug)
36,663✔
1124
        CPLDefaultErrorHandler(eErrClass, nError, pszErrorMsg);
2✔
1125
}
36,663✔
1126

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

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

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

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

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

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

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

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

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

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

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

1198
    fflush(fpLog);
×
1199
}
1200

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

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

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

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

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

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

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

1259
        pfnOldHandler = pfnErrorHandler;
19✔
1260

1261
        pfnErrorHandler = pfnErrorHandlerNew;
19✔
1262

1263
        pErrorHandlerUserData = pUserData;
19✔
1264
    }
1265

1266
    return pfnOldHandler;
19✔
1267
}
1268

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

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

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

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

1333
void CPL_STDCALL CPLPushErrorHandler(CPLErrorHandler pfnErrorHandlerNew)
146,778✔
1334

1335
{
1336
    CPLPushErrorHandlerEx(pfnErrorHandlerNew, nullptr);
146,778✔
1337
}
146,728✔
1338

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

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

1359
{
1360
    CPLErrorContext *psCtx = CPLGetErrorContext();
4,172,130✔
1361

1362
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
4,172,100✔
1363
    {
1364
        fprintf(stderr, "CPLPushErrorHandlerEx() failed.\n");
29✔
1365
        return;
×
1366
    }
1367

1368
    CPLErrorHandlerNode *psNode = static_cast<CPLErrorHandlerNode *>(
1369
        CPLMalloc(sizeof(CPLErrorHandlerNode)));
4,172,070✔
1370
    psNode->psNext = psCtx->psHandlerStack;
4,172,090✔
1371
    psNode->pfnHandler = pfnErrorHandlerNew;
4,172,090✔
1372
    psNode->pUserData = pUserData;
4,172,090✔
1373
    psNode->bCatchDebug = true;
4,172,090✔
1374
    psCtx->psHandlerStack = psNode;
4,172,090✔
1375
}
1376

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

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

1390
void CPL_STDCALL CPLPopErrorHandler()
4,172,030✔
1391

1392
{
1393
    CPLErrorContext *psCtx = CPLGetErrorContext();
4,172,030✔
1394

1395
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
4,172,050✔
1396
    {
1397
        fprintf(stderr, "CPLPopErrorHandler() failed.\n");
22✔
1398
        return;
×
1399
    }
1400

1401
    if (psCtx->psHandlerStack != nullptr)
4,172,030✔
1402
    {
1403
        CPLErrorHandlerNode *psNode = psCtx->psHandlerStack;
4,172,060✔
1404

1405
        psCtx->psHandlerStack = psNode->psNext;
4,172,060✔
1406
        VSIFree(psNode);
4,172,060✔
1407
    }
1408
}
1409

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

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

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

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

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

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

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

1478
void CPL_STDCALL CPLSetCurrentErrorHandlerCatchDebug(int bCatchDebug)
17,604✔
1479
{
1480
    CPLErrorContext *psCtx = CPLGetErrorContext();
17,604✔
1481

1482
    if (psCtx == nullptr || IS_PREFEFINED_ERROR_CTX(psCtx))
17,583✔
1483
    {
1484
        fprintf(stderr, "CPLSetCurrentErrorHandlerCatchDebug() failed.\n");
10✔
1485
        return;
×
1486
    }
1487

1488
    if (psCtx->psHandlerStack != nullptr)
17,573✔
1489
        psCtx->psHandlerStack->bCatchDebug = CPL_TO_BOOL(bCatchDebug);
17,577✔
1490
    else
1491
        gbCatchDebug = CPL_TO_BOOL(bCatchDebug);
×
1492
}
1493

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

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

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

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

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

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

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

1544
bool CPLIsDefaultErrorHandlerAndCatchDebug()
4,756✔
1545
{
1546
    CPLErrorContext *psCtx = CPLGetErrorContext();
4,756✔
1547
    return (psCtx == nullptr || psCtx->psHandlerStack == nullptr) &&
4,756✔
1548
           gbCatchDebug && pfnErrorHandler == CPLDefaultErrorHandler;
9,512✔
1549
}
1550

1551
/************************************************************************/
1552
/*                       CPLErrorHandlerAccumulator()                   */
1553
/************************************************************************/
1554

1555
static void CPL_STDCALL CPLErrorHandlerAccumulator(CPLErr eErr, CPLErrorNum no,
338✔
1556
                                                   const char *msg)
1557
{
1558
    std::vector<CPLErrorHandlerAccumulatorStruct> *paoErrors =
1559
        static_cast<std::vector<CPLErrorHandlerAccumulatorStruct> *>(
1560
            CPLGetErrorHandlerUserData());
338✔
1561
    paoErrors->push_back(CPLErrorHandlerAccumulatorStruct(eErr, no, msg));
338✔
1562
}
338✔
1563

1564
void CPLInstallErrorHandlerAccumulator(
67,253✔
1565
    std::vector<CPLErrorHandlerAccumulatorStruct> &aoErrors)
1566
{
1567
    CPLPushErrorHandlerEx(CPLErrorHandlerAccumulator, &aoErrors);
67,253✔
1568
}
67,246✔
1569

1570
void CPLUninstallErrorHandlerAccumulator()
67,229✔
1571
{
1572
    CPLPopErrorHandler();
67,229✔
1573
}
67,241✔
1574

1575
/************************************************************************/
1576
/*               CPLErrorStateBackuper::CPLErrorStateBackuper()         */
1577
/************************************************************************/
1578

1579
CPLErrorStateBackuper::CPLErrorStateBackuper(CPLErrorHandler hHandler)
73,937✔
1580
    : m_nLastErrorNum(CPLGetLastErrorNo()),
73,937✔
1581
      m_nLastErrorType(CPLGetLastErrorType()),
147,778✔
1582
      m_osLastErrorMsg(CPLGetLastErrorMsg()),
1583
      m_nLastErrorCounter(CPLGetErrorCounter()),
147,830✔
1584
      m_poErrorHandlerPusher(
1585
          hHandler ? std::make_unique<CPLErrorHandlerPusher>(hHandler)
1586
                   : nullptr)
73,882✔
1587
{
1588
}
73,877✔
1589

1590
/************************************************************************/
1591
/*               CPLErrorStateBackuper::~CPLErrorStateBackuper()        */
1592
/************************************************************************/
1593

1594
CPLErrorStateBackuper::~CPLErrorStateBackuper()
73,908✔
1595
{
1596
    CPLErrorSetState(m_nLastErrorType, m_nLastErrorNum,
73,938✔
1597
                     m_osLastErrorMsg.c_str(), &m_nLastErrorCounter);
1598
}
73,908✔
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