LCOV - code coverage report
Current view: top level - port - cpl_vsisimple.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 180 260 69.2 %
Date: 2024-11-21 22:18:42 Functions: 28 42 66.7 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Common Portability Library
       4             :  * Purpose:  Simple implementation of POSIX VSI functions.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, Frank Warmerdam
       9             :  * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************
      13             :  *
      14             :  * NB: Note that in wrappers we are always saving the error state (errno
      15             :  * variable) to avoid side effects during debug prints or other possible
      16             :  * standard function calls (error states will be overwritten after such
      17             :  * a call).
      18             :  *
      19             :  ****************************************************************************/
      20             : 
      21             : // Must be done before including cpl_port.h
      22             : // We need __MSVCRT_VERSION__ >= 0x0700 to have "_aligned_malloc"
      23             : // Latest versions of mingw32 define it, but with older ones,
      24             : // we need to define it manually.
      25             : #if defined(__MINGW32__)
      26             : #include <windows.h>
      27             : #ifndef __MSVCRT_VERSION__
      28             : #define __MSVCRT_VERSION__ 0x0700
      29             : #endif
      30             : #endif
      31             : 
      32             : #include "cpl_port.h"
      33             : #include "cpl_vsi.h"
      34             : 
      35             : #include <algorithm>
      36             : #include <cerrno>
      37             : #include <cstdarg>
      38             : #include <cstddef>
      39             : #include <cstdio>
      40             : #include <cstdlib>
      41             : #include <cstring>
      42             : #include <ctime>
      43             : #include <limits>
      44             : #if HAVE_SYS_STAT_H
      45             : #include <sys/stat.h>
      46             : #endif
      47             : #if HAVE_GETRLIMIT
      48             : #include <sys/time.h>
      49             : #include <sys/resource.h>
      50             : #endif
      51             : 
      52             : #include "cpl_config.h"
      53             : #include "cpl_error.h"
      54             : #include "cpl_string.h"
      55             : 
      56             : #ifdef _WIN32
      57             : #include <malloc.h>  // For _aligned_malloc
      58             : #endif
      59             : 
      60             : // Uncomment to check consistent usage of VSIMalloc(), VSIRealloc(),
      61             : // VSICalloc(), VSIFree(), VSIStrdup().
      62             : // #define DEBUG_VSIMALLOC
      63             : 
      64             : // Uncomment to compute memory usage statistics.
      65             : // DEBUG_VSIMALLOC must also be defined.
      66             : // #define DEBUG_VSIMALLOC_STATS
      67             : 
      68             : // Highly experimental, and likely buggy. Do not use, except for fixing it!
      69             : // DEBUG_VSIMALLOC must also be defined.
      70             : // #define DEBUG_VSIMALLOC_MPROTECT
      71             : 
      72             : #ifdef DEBUG_VSIMALLOC_MPROTECT
      73             : #include <sys/mman.h>
      74             : #endif
      75             : 
      76             : // Uncomment to print every memory allocation or deallocation.
      77             : // DEBUG_VSIMALLOC must also be defined.
      78             : // #define DEBUG_VSIMALLOC_VERBOSE
      79             : 
      80             : // Number of bytes of the malloc/calloc/free that triggers a debug trace.
      81             : // Can be 0 for all allocs.
      82             : #define THRESHOLD_PRINT 10000
      83             : 
      84             : // Uncomment to print GDAL block cache use.
      85             : // Only used if DEBUG_VSIMALLOC_VERBOSE is enabled.
      86             : // #define DEBUG_BLOCK_CACHE_USE
      87             : 
      88             : #ifdef DEBUG_BLOCK_CACHE_USE
      89             : extern "C" GIntBig CPL_DLL CPL_STDCALL GDALGetCacheUsed64(void);
      90             : #endif
      91             : 
      92             : /* Unix or Windows NT/2000/XP */
      93             : #if !defined(_WIN32)
      94             : #include <unistd.h>
      95             : #else
      96             : #include <io.h>
      97             : #include <fcntl.h>
      98             : #include <direct.h>
      99             : #endif
     100             : 
     101             : /************************************************************************/
     102             : /*                              VSIFOpen()                              */
     103             : /************************************************************************/
     104             : 
     105         117 : FILE *VSIFOpen(const char *pszFilename, const char *pszAccess)
     106             : 
     107             : {
     108             : #if defined(_WIN32)
     109             :     FILE *fp = nullptr;
     110             :     if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
     111             :     {
     112             :         wchar_t *pwszFilename =
     113             :             CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
     114             :         wchar_t *pwszAccess =
     115             :             CPLRecodeToWChar(pszAccess, CPL_ENC_UTF8, CPL_ENC_UCS2);
     116             : 
     117             :         fp = _wfopen(pwszFilename, pwszAccess);
     118             : 
     119             :         CPLFree(pwszFilename);
     120             :         CPLFree(pwszAccess);
     121             :     }
     122             :     else
     123             :     {
     124             :         // Are the casts really necessary?
     125             :         fp = fopen(const_cast<char *>(pszFilename),
     126             :                    const_cast<char *>(pszAccess));
     127             :     }
     128             : #else
     129         117 :     FILE *fp = fopen(pszFilename, pszAccess);
     130             : #endif
     131             : 
     132             : #ifdef VSI_DEBUG
     133             :     // Capture the error from fopen to avoid being overwritten by errors
     134             :     // from VSIDebug3.
     135             :     const int nError = errno;
     136             :     VSIDebug3("VSIFOpen(%s,%s) = %p", pszFilename, pszAccess, fp);
     137             :     errno = nError;
     138             : #endif
     139             : 
     140         117 :     return fp;
     141             : }
     142             : 
     143             : /************************************************************************/
     144             : /*                             VSIFClose()                              */
     145             : /************************************************************************/
     146             : 
     147         102 : int VSIFClose(FILE *fp)
     148             : 
     149             : {
     150             :     VSIDebug1("VSIClose(%p)", fp);
     151             : 
     152         102 :     return fclose(fp);
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                              VSIFSeek()                              */
     157             : /************************************************************************/
     158             : 
     159           0 : int VSIFSeek(FILE *fp, long nOffset, int nWhence)
     160             : 
     161             : {
     162             : #ifdef DEBUG
     163             :     // To workaround Coverity strange warning about potential negative seek
     164             :     // CID 1340084 when called from dgnwrite.cpp.
     165           0 :     if (nWhence == SEEK_SET && nOffset < 0)
     166           0 :         return -1;
     167             : #endif
     168           0 :     int nResult = fseek(fp, nOffset, nWhence);
     169             : 
     170             : #ifdef VSI_DEBUG
     171             :     // Capture the error from fseek to avoid being overwritten by errors
     172             :     // from VSIDebug.
     173             :     const int nError = errno;
     174             : 
     175             :     if (nWhence == SEEK_SET)
     176             :     {
     177             :         VSIDebug3("VSIFSeek(%p,%ld,SEEK_SET) = %d", fp, nOffset, nResult);
     178             :     }
     179             :     else if (nWhence == SEEK_END)
     180             :     {
     181             :         VSIDebug3("VSIFSeek(%p,%ld,SEEK_END) = %d", fp, nOffset, nResult);
     182             :     }
     183             :     else if (nWhence == SEEK_CUR)
     184             :     {
     185             :         VSIDebug3("VSIFSeek(%p,%ld,SEEK_CUR) = %d", fp, nOffset, nResult);
     186             :     }
     187             :     else
     188             :     {
     189             :         VSIDebug4("VSIFSeek(%p,%ld,%d-Unknown) = %d", fp, nOffset, nWhence,
     190             :                   nResult);
     191             :     }
     192             : 
     193             :     errno = nError;
     194             : #endif
     195             : 
     196           0 :     return nResult;
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /*                              VSIFTell()                              */
     201             : /************************************************************************/
     202             : 
     203           0 : long VSIFTell(FILE *fp)
     204             : 
     205             : {
     206           0 :     const long nOffset = ftell(fp);
     207             : 
     208             : #ifdef VSI_DEBUG
     209             :     // Capture the error from ftell to avoid being overwritten by errors
     210             :     // from VSIDebug.
     211             :     const int nError = errno;
     212             :     VSIDebug2("VSIFTell(%p) = %ld", fp, nOffset);
     213             :     errno = nError;
     214             : #endif
     215             : 
     216           0 :     return nOffset;
     217             : }
     218             : 
     219             : /************************************************************************/
     220             : /*                             VSIRewind()                              */
     221             : /************************************************************************/
     222             : 
     223           0 : void VSIRewind(FILE *fp)
     224             : 
     225             : {
     226             :     VSIDebug1("VSIRewind(%p)", fp);
     227           0 :     rewind(fp);
     228             : #ifdef VSI_DEBUG
     229             :     // Capture the error rewind ftell to avoid being overwritten by errors
     230             :     // from VSIDebug.
     231             :     const int nError = errno;
     232             :     VSIDebug2("VSIRewind(%p) errno = %d", fp, nError);
     233             :     errno = nError;
     234             : #endif
     235           0 : }
     236             : 
     237             : /************************************************************************/
     238             : /*                              VSIFRead()                              */
     239             : /************************************************************************/
     240             : 
     241           0 : size_t VSIFRead(void *pBuffer, size_t nSize, size_t nCount, FILE *fp)
     242             : 
     243             : {
     244           0 :     const size_t nResult = fread(pBuffer, nSize, nCount, fp);
     245             : 
     246             : #ifdef VSI_DEBUG
     247             :     // Capture the error from fread to avoid being overwritten by errors
     248             :     // from VSIDebug.
     249             :     const int nError = errno;
     250             :     VSIDebug4("VSIFRead(%p,%ld,%ld) = %ld", fp, static_cast<long>(nSize),
     251             :               static_cast<long>(nCount), static_cast<long>(nResult));
     252             :     errno = nError;
     253             : #endif
     254             : 
     255           0 :     return nResult;
     256             : }
     257             : 
     258             : /************************************************************************/
     259             : /*                             VSIFWrite()                              */
     260             : /************************************************************************/
     261             : 
     262        1066 : size_t VSIFWrite(const void *pBuffer, size_t nSize, size_t nCount, FILE *fp)
     263             : 
     264             : {
     265        1066 :     const size_t nResult = fwrite(pBuffer, nSize, nCount, fp);
     266             : 
     267             : #ifdef VSI_DEBUG
     268             :     // Capture the error from fwrite to avoid being overwritten by errors
     269             :     // from VSIDebug.
     270             :     const int nError = errno;
     271             :     VSIDebug4("VSIFWrite(%p,%ld,%ld) = %ld", fp, static_cast<long>(nSize),
     272             :               static_cast<long>(nCount), static_cast<long>(nResult));
     273             :     errno = nError;
     274             : #endif
     275             : 
     276        1066 :     return nResult;
     277             : }
     278             : 
     279             : /************************************************************************/
     280             : /*                             VSIFFlush()                              */
     281             : /************************************************************************/
     282             : 
     283           0 : void VSIFFlush(FILE *fp)
     284             : 
     285             : {
     286             : #ifdef VSI_DEBUG
     287             :     VSIDebug1("VSIFFlush(%p)", fp);
     288             :     const int result =
     289             : #endif
     290           0 :         fflush(fp);
     291             : 
     292             : #ifdef VSI_DEBUG
     293             :     // Capture the error rewind ftell to avoid being overwritten by errors
     294             :     // from VSIDebug.
     295             :     const int nError = errno;
     296             :     VSIDebug2("VSIRewind(%p) errno = %d", fp, nError);
     297             :     if (result != 0)
     298             :     {
     299             :         CPLError(CE_Failure, CPLE_FileIO, "Flush failed.  errno = %d", nError);
     300             :     }
     301             :     errno = nError;
     302             : #endif
     303           0 : }
     304             : 
     305             : /************************************************************************/
     306             : /*                              VSIFGets()                              */
     307             : /************************************************************************/
     308             : 
     309           0 : char *VSIFGets(char *pszBuffer, int nBufferSize, FILE *fp)
     310             : 
     311             : {
     312           0 :     return fgets(pszBuffer, nBufferSize, fp);
     313             : }
     314             : 
     315             : /************************************************************************/
     316             : /*                              VSIFGetc()                              */
     317             : /************************************************************************/
     318             : 
     319           0 : int VSIFGetc(FILE *fp)
     320             : 
     321             : {
     322           0 :     return fgetc(fp);
     323             : }
     324             : 
     325             : /************************************************************************/
     326             : /*                             VSIUngetc()                              */
     327             : /************************************************************************/
     328             : 
     329           0 : int VSIUngetc(int c, FILE *fp)
     330             : 
     331             : {
     332           0 :     return ungetc(c, fp);
     333             : }
     334             : 
     335             : /************************************************************************/
     336             : /*                             VSIFPrintf()                             */
     337             : /*                                                                      */
     338             : /*      This is a little more complicated than just calling             */
     339             : /*      fprintf() because of the variable arguments.  Instead we        */
     340             : /*      have to use vfprintf().                                         */
     341             : /************************************************************************/
     342             : 
     343           0 : int VSIFPrintf(FILE *fp, CPL_FORMAT_STRING(const char *pszFormat), ...)
     344             : 
     345             : {
     346             :     va_list args;
     347             : 
     348           0 :     va_start(args, pszFormat);
     349           0 :     const int nReturn = vfprintf(fp, pszFormat, args);
     350           0 :     va_end(args);
     351             : 
     352           0 :     return nReturn;
     353             : }
     354             : 
     355             : /************************************************************************/
     356             : /*                              VSIFEof()                               */
     357             : /************************************************************************/
     358             : 
     359           0 : int VSIFEof(FILE *fp)
     360             : 
     361             : {
     362           0 :     return feof(fp);
     363             : }
     364             : 
     365             : /************************************************************************/
     366             : /*                              VSIFPuts()                              */
     367             : /************************************************************************/
     368             : 
     369           0 : int VSIFPuts(const char *pszString, FILE *fp)
     370             : 
     371             : {
     372           0 :     return fputs(pszString, fp);
     373             : }
     374             : 
     375             : /************************************************************************/
     376             : /*                              VSIFPutc()                              */
     377             : /************************************************************************/
     378             : 
     379           0 : int VSIFPutc(int nChar, FILE *fp)
     380             : 
     381             : {
     382           0 :     return fputc(nChar, fp);
     383             : }
     384             : 
     385             : #ifdef DEBUG_VSIMALLOC_STATS
     386             : #include "cpl_multiproc.h"
     387             : 
     388             : static CPLMutex *hMemStatMutex = nullptr;
     389             : static size_t nCurrentTotalAllocs = 0;
     390             : static size_t nMaxTotalAllocs = 0;
     391             : static GUIntBig nVSIMallocs = 0;
     392             : static GUIntBig nVSICallocs = 0;
     393             : static GUIntBig nVSIReallocs = 0;
     394             : static GUIntBig nVSIFrees = 0;
     395             : 
     396             : /************************************************************************/
     397             : /*                         VSIShowMemStats()                            */
     398             : /************************************************************************/
     399             : 
     400             : void VSIShowMemStats();
     401             : 
     402             : void VSIShowMemStats()
     403             : {
     404             :     char *pszShowMemStats = getenv("CPL_SHOW_MEM_STATS");
     405             :     if (pszShowMemStats == nullptr || pszShowMemStats[0] == '\0')
     406             :         return;
     407             :     printf("Current VSI memory usage        : " CPL_FRMT_GUIB " bytes\n", /*ok*/
     408             :            static_cast<GUIntBig>(nCurrentTotalAllocs));
     409             :     printf("Maximum VSI memory usage        : " CPL_FRMT_GUIB " bytes\n", /*ok*/
     410             :            static_cast<GUIntBig>(nMaxTotalAllocs));
     411             :     printf("Number of calls to VSIMalloc()  : " CPL_FRMT_GUIB "\n", /*ok*/
     412             :            nVSIMallocs);
     413             :     printf("Number of calls to VSICalloc()  : " CPL_FRMT_GUIB "\n", /*ok*/
     414             :            nVSICallocs);
     415             :     printf("Number of calls to VSIRealloc() : " CPL_FRMT_GUIB "\n", /*ok*/
     416             :            nVSIReallocs);
     417             :     printf("Number of calls to VSIFree()    : " CPL_FRMT_GUIB "\n", /*ok*/
     418             :            nVSIFrees);
     419             :     printf("VSIMalloc + VSICalloc - VSIFree : " CPL_FRMT_GUIB "\n", /*ok*/
     420             :            nVSIMallocs + nVSICallocs - nVSIFrees);
     421             : }
     422             : #endif
     423             : 
     424             : #ifdef DEBUG_VSIMALLOC
     425             : static GIntBig nMaxPeakAllocSize = -1;
     426             : static GIntBig nMaxCumulAllocSize = -1;
     427             : #endif
     428             : 
     429             : /************************************************************************/
     430             : /*                             VSICalloc()                              */
     431             : /************************************************************************/
     432             : 
     433             : #ifndef DEBUG_VSIMALLOC
     434             : 
     435             : /** Analog of calloc(). Use VSIFree() to free */
     436    31718400 : void *VSICalloc(size_t nCount, size_t nSize)
     437             : {
     438             :     // cppcheck-suppress invalidFunctionArg
     439    31718400 :     return calloc(nCount, nSize);
     440             : }
     441             : 
     442             : #else  // DEBUG_VSIMALLOC
     443             : 
     444             : void *VSICalloc(size_t nCount, size_t nSize)
     445             : {
     446             :     size_t nMul = nCount * nSize;
     447             :     if (nCount != 0 && nMul / nCount != nSize)
     448             :     {
     449             :         fprintf(stderr, "Overflow in VSICalloc(%d, %d)\n", /*ok*/
     450             :                 static_cast<int>(nCount), static_cast<int>(nSize));
     451             :         return nullptr;
     452             :     }
     453             :     if (nMaxPeakAllocSize < 0)
     454             :     {
     455             :         char *pszMaxPeakAllocSize = getenv("CPL_MAX_PEAK_ALLOC_SIZE");
     456             :         nMaxPeakAllocSize = pszMaxPeakAllocSize ? atoi(pszMaxPeakAllocSize) : 0;
     457             :         char *pszMaxCumulAllocSize = getenv("CPL_MAX_CUMUL_ALLOC_SIZE");
     458             :         nMaxCumulAllocSize =
     459             :             pszMaxCumulAllocSize ? atoi(pszMaxCumulAllocSize) : 0;
     460             :     }
     461             :     if (nMaxPeakAllocSize > 0 && static_cast<GIntBig>(nMul) > nMaxPeakAllocSize)
     462             :         return nullptr;
     463             : #ifdef DEBUG_VSIMALLOC_STATS
     464             :     if (nMaxCumulAllocSize > 0 &&
     465             :         static_cast<GIntBig>(nCurrentTotalAllocs) + static_cast<GIntBig>(nMul) >
     466             :             nMaxCumulAllocSize)
     467             :         return nullptr;
     468             : #endif
     469             : 
     470             : #ifdef DEBUG_VSIMALLOC_MPROTECT
     471             :     char *ptr = nullptr;
     472             :     const size_t nPageSize = getpagesize();
     473             :     const size_t nRequestedSize =
     474             :         (3 * sizeof(void *) + nMul + nPageSize - 1) & ~(nPageSize - 1);
     475             :     if (nRequestedSize < nMul)
     476             :         return nullptr;
     477             :     posix_memalign((void **)&ptr, nPageSize, nRequestedSize);
     478             :     if (ptr == nullptr)
     479             :         return nullptr;
     480             :     memset(ptr + 2 * sizeof(void *), 0, nMul);
     481             : #else
     482             :     const size_t nRequestedSize = 3 * sizeof(void *) + nMul;
     483             :     if (nRequestedSize < nMul)
     484             :         return nullptr;
     485             :     char *ptr = static_cast<char *>(calloc(1, nRequestedSize));
     486             :     if (ptr == nullptr)
     487             :         return nullptr;
     488             : #endif
     489             : 
     490             :     ptr[0] = 'V';
     491             :     ptr[1] = 'S';
     492             :     ptr[2] = 'I';
     493             :     ptr[3] = 'M';
     494             :     // cppcheck-suppress pointerSize
     495             :     memcpy(ptr + sizeof(void *), &nMul, sizeof(void *));
     496             :     ptr[2 * sizeof(void *) + nMul + 0] = 'E';
     497             :     ptr[2 * sizeof(void *) + nMul + 1] = 'V';
     498             :     ptr[2 * sizeof(void *) + nMul + 2] = 'S';
     499             :     ptr[2 * sizeof(void *) + nMul + 3] = 'I';
     500             : #if defined(DEBUG_VSIMALLOC_STATS) || defined(DEBUG_VSIMALLOC_VERBOSE)
     501             :     {
     502             :         CPLMutexHolderD(&hMemStatMutex);
     503             : #ifdef DEBUG_VSIMALLOC_VERBOSE
     504             :         if (nMul > THRESHOLD_PRINT)
     505             :         {
     506             :             fprintf(stderr, /*ok*/
     507             :                     "Thread[%p] VSICalloc(%d,%d) = %p"
     508             : #ifdef DEBUG_VSIMALLOC_STATS
     509             :                     ", current_cumul = " CPL_FRMT_GUIB
     510             : #ifdef DEBUG_BLOCK_CACHE_USE
     511             :                     ", block_cache_used = " CPL_FRMT_GIB
     512             : #endif
     513             :                     ", mal+cal-free = %d"
     514             : #endif
     515             :                     "\n",
     516             :                     (void *)CPLGetPID(), static_cast<int>(nCount),
     517             :                     static_cast<int>(nSize), ptr + 2 * sizeof(void *)
     518             : #ifdef DEBUG_VSIMALLOC_STATS
     519             :                                                  ,
     520             :                     static_cast<GUIntBig>(nCurrentTotalAllocs + nMul)
     521             : #ifdef DEBUG_BLOCK_CACHE_USE
     522             :                         ,
     523             :                     GDALGetCacheUsed64()
     524             : #endif
     525             :                         ,
     526             :                     static_cast<int>(nVSIMallocs + nVSICallocs - nVSIFrees)
     527             : #endif
     528             :             );
     529             :         }
     530             : #endif
     531             : #ifdef DEBUG_VSIMALLOC_STATS
     532             :         nVSICallocs++;
     533             :         if (nMaxTotalAllocs == 0)
     534             :             atexit(VSIShowMemStats);
     535             :         nCurrentTotalAllocs += nMul;
     536             :         if (nCurrentTotalAllocs > nMaxTotalAllocs)
     537             :             nMaxTotalAllocs = nCurrentTotalAllocs;
     538             : #endif
     539             :     }
     540             : #endif
     541             :     // cppcheck-suppress memleak
     542             :     return ptr + 2 * sizeof(void *);
     543             : }
     544             : #endif  // DEBUG_VSIMALLOC
     545             : 
     546             : /************************************************************************/
     547             : /*                             VSIMalloc()                              */
     548             : /************************************************************************/
     549             : 
     550             : #ifndef DEBUG_VSIMALLOC
     551             : /** Analog of malloc(). Use VSIFree() to free */
     552    83416900 : void *VSIMalloc(size_t nSize)
     553             : 
     554             : {
     555    83416900 :     return malloc(nSize);
     556             : }
     557             : 
     558             : #else  // DEBUG_VSIMALLOC
     559             : 
     560             : void *VSIMalloc(size_t nSize)
     561             : 
     562             : {
     563             :     if (nMaxPeakAllocSize < 0)
     564             :     {
     565             :         char *pszMaxPeakAllocSize = getenv("CPL_MAX_PEAK_ALLOC_SIZE");
     566             :         nMaxPeakAllocSize = pszMaxPeakAllocSize ? atoi(pszMaxPeakAllocSize) : 0;
     567             :         char *pszMaxCumulAllocSize = getenv("CPL_MAX_CUMUL_ALLOC_SIZE");
     568             :         nMaxCumulAllocSize =
     569             :             pszMaxCumulAllocSize ? atoi(pszMaxCumulAllocSize) : 0;
     570             :     }
     571             :     if (nMaxPeakAllocSize > 0 &&
     572             :         static_cast<GIntBig>(nSize) > nMaxPeakAllocSize)
     573             :         return nullptr;
     574             : #ifdef DEBUG_VSIMALLOC_STATS
     575             :     if (nMaxCumulAllocSize > 0 && static_cast<GIntBig>(nCurrentTotalAllocs) +
     576             :                                           static_cast<GIntBig>(nSize) >
     577             :                                       nMaxCumulAllocSize)
     578             :         return nullptr;
     579             : #endif  // DEBUG_VSIMALLOC_STATS
     580             : 
     581             : #ifdef DEBUG_VSIMALLOC_MPROTECT
     582             :     char *ptr = nullptr;
     583             :     const size_t nPageSize = getpagesize();
     584             :     const size_t nRequestedSize =
     585             :         (3 * sizeof(void *) + nSize + nPageSize - 1) & ~(nPageSize - 1);
     586             :     if (nRequestedSize < nSize)
     587             :         return nullptr;
     588             :     posix_memalign((void **)&ptr, nPageSize, nRequestedSize);
     589             : #else
     590             :     const size_t nRequestedSize = 3 * sizeof(void *) + nSize;
     591             :     if (nRequestedSize < nSize)
     592             :         return nullptr;
     593             :     char *ptr = static_cast<char *>(malloc(nRequestedSize));
     594             : #endif  // DEBUG_VSIMALLOC_MPROTECT
     595             :     if (ptr == nullptr)
     596             :         return nullptr;
     597             :     ptr[0] = 'V';
     598             :     ptr[1] = 'S';
     599             :     ptr[2] = 'I';
     600             :     ptr[3] = 'M';
     601             :     // cppcheck-suppress pointerSize
     602             :     memcpy(ptr + sizeof(void *), &nSize, sizeof(void *));
     603             :     ptr[2 * sizeof(void *) + nSize + 0] = 'E';
     604             :     ptr[2 * sizeof(void *) + nSize + 1] = 'V';
     605             :     ptr[2 * sizeof(void *) + nSize + 2] = 'S';
     606             :     ptr[2 * sizeof(void *) + nSize + 3] = 'I';
     607             : #if defined(DEBUG_VSIMALLOC_STATS) || defined(DEBUG_VSIMALLOC_VERBOSE)
     608             :     {
     609             :         CPLMutexHolderD(&hMemStatMutex);
     610             : #ifdef DEBUG_VSIMALLOC_VERBOSE
     611             :         if (nSize > THRESHOLD_PRINT)
     612             :         {
     613             :             fprintf(stderr, /*ok*/
     614             :                     "Thread[%p] VSIMalloc(%d) = %p"
     615             : #ifdef DEBUG_VSIMALLOC_STATS
     616             :                     ", current_cumul = " CPL_FRMT_GUIB
     617             : #ifdef DEBUG_BLOCK_CACHE_USE
     618             :                     ", block_cache_used = " CPL_FRMT_GIB
     619             : #endif
     620             :                     ", mal+cal-free = %d"
     621             : #endif
     622             :                     "\n",
     623             :                     (void *)CPLGetPID(), static_cast<int>(nSize),
     624             :                     ptr + 2 * sizeof(void *)
     625             : #ifdef DEBUG_VSIMALLOC_STATS
     626             :                         ,
     627             :                     static_cast<GUIntBig>(nCurrentTotalAllocs + nSize)
     628             : #ifdef DEBUG_BLOCK_CACHE_USE
     629             :                         ,
     630             :                     GDALGetCacheUsed64()
     631             : #endif
     632             :                         ,
     633             :                     static_cast<int>(nVSIMallocs + nVSICallocs - nVSIFrees)
     634             : #endif
     635             :             );
     636             :         }
     637             : #endif  // DEBUG_VSIMALLOC_VERBOSE
     638             : #ifdef DEBUG_VSIMALLOC_STATS
     639             :         nVSIMallocs++;
     640             :         if (nMaxTotalAllocs == 0)
     641             :             atexit(VSIShowMemStats);
     642             :         nCurrentTotalAllocs += nSize;
     643             :         if (nCurrentTotalAllocs > nMaxTotalAllocs)
     644             :             nMaxTotalAllocs = nCurrentTotalAllocs;
     645             : #endif  // DEBUG_VSIMALLOC_STATS
     646             :     }
     647             : #endif  // DEBUG_VSIMALLOC_STATS || DEBUG_VSIMALLOC_VERBOSE
     648             :     // cppcheck-suppress memleak
     649             :     return ptr + 2 * sizeof(void *);
     650             : }
     651             : 
     652             : static void VSICheckMarkerBegin(char *ptr)
     653             : {
     654             :     if (memcmp(ptr, "VSIM", 4) != 0)
     655             :     {
     656             :         CPLError(CE_Fatal, CPLE_AppDefined,
     657             :                  "Inconsistent use of VSI memory allocation primitives "
     658             :                  "for %p : %c%c%c%c",
     659             :                  ptr, ptr[0], ptr[1], ptr[2], ptr[3]);
     660             :     }
     661             : }
     662             : 
     663             : static void VSICheckMarkerEnd(char *ptr, size_t nEnd)
     664             : {
     665             :     if (memcmp(ptr + nEnd, "EVSI", 4) != 0)
     666             :     {
     667             :         CPLError(CE_Fatal, CPLE_AppDefined,
     668             :                  "Memory has been written after the end of %p", ptr);
     669             :     }
     670             : }
     671             : 
     672             : #endif  // DEBUG_VSIMALLOC
     673             : 
     674             : /************************************************************************/
     675             : /*                             VSIRealloc()                             */
     676             : /************************************************************************/
     677             : 
     678             : /** Analog of realloc(). Use VSIFree() to free */
     679    21459100 : void *VSIRealloc(void *pData, size_t nNewSize)
     680             : 
     681             : {
     682             : #ifdef DEBUG_VSIMALLOC
     683             :     if (pData == nullptr)
     684             :         return VSIMalloc(nNewSize);
     685             : 
     686             :     char *ptr = ((char *)pData) - 2 * sizeof(void *);
     687             :     VSICheckMarkerBegin(ptr);
     688             : 
     689             :     size_t nOldSize = 0;
     690             :     // cppcheck-suppress pointerSize
     691             :     memcpy(&nOldSize, ptr + sizeof(void *), sizeof(void *));
     692             :     VSICheckMarkerEnd(ptr, 2 * sizeof(void *) + nOldSize);
     693             : 
     694             :     if (nMaxPeakAllocSize < 0)
     695             :     {
     696             :         char *pszMaxPeakAllocSize = getenv("CPL_MAX_PEAK_ALLOC_SIZE");
     697             :         nMaxPeakAllocSize = pszMaxPeakAllocSize ? atoi(pszMaxPeakAllocSize) : 0;
     698             :     }
     699             :     if (nMaxPeakAllocSize > 0 &&
     700             :         static_cast<GIntBig>(nNewSize) > nMaxPeakAllocSize)
     701             :         return nullptr;
     702             : #ifdef DEBUG_VSIMALLOC_STATS
     703             :     if (nMaxCumulAllocSize > 0 && static_cast<GIntBig>(nCurrentTotalAllocs) +
     704             :                                           static_cast<GIntBig>(nNewSize) -
     705             :                                           static_cast<GIntBig>(nOldSize) >
     706             :                                       nMaxCumulAllocSize)
     707             :         return nullptr;
     708             : #endif
     709             : 
     710             :     ptr[2 * sizeof(void *) + nOldSize + 0] = 'I';
     711             :     ptr[2 * sizeof(void *) + nOldSize + 1] = 'S';
     712             :     ptr[2 * sizeof(void *) + nOldSize + 2] = 'V';
     713             :     ptr[2 * sizeof(void *) + nOldSize + 3] = 'E';
     714             : 
     715             : #ifdef DEBUG_VSIMALLOC_MPROTECT
     716             :     char *newptr = nullptr;
     717             :     const size_t nPageSize = getpagesize();
     718             :     const size_t nRequestedSize =
     719             :         (nNewSize + 3 * sizeof(void *) + nPageSize - 1) & ~(nPageSize - 1);
     720             :     if (nRequestedSize < nNewSize)
     721             :     {
     722             :         ptr[2 * sizeof(void *) + nOldSize + 0] = 'E';
     723             :         ptr[2 * sizeof(void *) + nOldSize + 1] = 'V';
     724             :         ptr[2 * sizeof(void *) + nOldSize + 2] = 'S';
     725             :         ptr[2 * sizeof(void *) + nOldSize + 3] = 'I';
     726             :         return nullptr;
     727             :     }
     728             :     posix_memalign((void **)&newptr, nPageSize, nRequestedSize);
     729             :     if (newptr == nullptr)
     730             :     {
     731             :         ptr[2 * sizeof(void *) + nOldSize + 0] = 'E';
     732             :         ptr[2 * sizeof(void *) + nOldSize + 1] = 'V';
     733             :         ptr[2 * sizeof(void *) + nOldSize + 2] = 'S';
     734             :         ptr[2 * sizeof(void *) + nOldSize + 3] = 'I';
     735             :         return nullptr;
     736             :     }
     737             :     memcpy(newptr + 2 * sizeof(void *), pData, nOldSize);
     738             :     ptr[0] = 'M';
     739             :     ptr[1] = 'I';
     740             :     ptr[2] = 'S';
     741             :     ptr[3] = 'V';
     742             :     free(ptr);
     743             :     newptr[0] = 'V';
     744             :     newptr[1] = 'S';
     745             :     newptr[2] = 'I';
     746             :     newptr[3] = 'M';
     747             : #else
     748             :     const size_t nRequestedSize = 3 * sizeof(void *) + nNewSize;
     749             :     if (nRequestedSize < nNewSize)
     750             :     {
     751             :         ptr[2 * sizeof(void *) + nOldSize + 0] = 'E';
     752             :         ptr[2 * sizeof(void *) + nOldSize + 1] = 'V';
     753             :         ptr[2 * sizeof(void *) + nOldSize + 2] = 'S';
     754             :         ptr[2 * sizeof(void *) + nOldSize + 3] = 'I';
     755             :         return nullptr;
     756             :     }
     757             :     void *newptr = realloc(ptr, nRequestedSize);
     758             :     if (newptr == nullptr)
     759             :     {
     760             :         ptr[2 * sizeof(void *) + nOldSize + 0] = 'E';
     761             :         ptr[2 * sizeof(void *) + nOldSize + 1] = 'V';
     762             :         ptr[2 * sizeof(void *) + nOldSize + 2] = 'S';
     763             :         ptr[2 * sizeof(void *) + nOldSize + 3] = 'I';
     764             :         return nullptr;
     765             :     }
     766             : #endif
     767             :     ptr = static_cast<char *>(newptr);
     768             :     // cppcheck-suppress pointerSize
     769             :     memcpy(ptr + sizeof(void *), &nNewSize, sizeof(void *));
     770             :     ptr[2 * sizeof(void *) + nNewSize + 0] = 'E';
     771             :     ptr[2 * sizeof(void *) + nNewSize + 1] = 'V';
     772             :     ptr[2 * sizeof(void *) + nNewSize + 2] = 'S';
     773             :     ptr[2 * sizeof(void *) + nNewSize + 3] = 'I';
     774             : 
     775             : #if defined(DEBUG_VSIMALLOC_STATS) || defined(DEBUG_VSIMALLOC_VERBOSE)
     776             :     {
     777             :         CPLMutexHolderD(&hMemStatMutex);
     778             : #ifdef DEBUG_VSIMALLOC_VERBOSE
     779             :         if (nNewSize > THRESHOLD_PRINT)
     780             :         {
     781             :             fprintf(
     782             :                 stderr,
     783             :                 "Thread[%p] VSIRealloc(%p, %d) = %p" /*ok*/
     784             : #ifdef DEBUG_VSIMALLOC_STATS
     785             :                 ", current_cumul = " CPL_FRMT_GUIB
     786             : #ifdef DEBUG_BLOCK_CACHE_USE
     787             :                 ", block_cache_used = " CPL_FRMT_GIB
     788             : #endif
     789             :                 ", mal+cal-free = %d"
     790             : #endif
     791             :                 "\n",
     792             :                 (void *)CPLGetPID(), pData, static_cast<int>(nNewSize),
     793             :                 ptr + 2 * sizeof(void *)
     794             : #ifdef DEBUG_VSIMALLOC_STATS
     795             :                     ,
     796             :                 static_cast<GUIntBig>(nCurrentTotalAllocs - nOldSize + nNewSize)
     797             : #ifdef DEBUG_BLOCK_CACHE_USE
     798             :                     ,
     799             :                 GDALGetCacheUsed64()
     800             : #endif
     801             :                     ,
     802             :                 static_cast<int>(nVSIMallocs + nVSICallocs - nVSIFrees)
     803             : #endif
     804             :             );
     805             :         }
     806             : #endif
     807             : #ifdef DEBUG_VSIMALLOC_STATS
     808             :         nVSIReallocs++;
     809             :         nCurrentTotalAllocs -= nOldSize;
     810             :         nCurrentTotalAllocs += nNewSize;
     811             :         if (nCurrentTotalAllocs > nMaxTotalAllocs)
     812             :             nMaxTotalAllocs = nCurrentTotalAllocs;
     813             : #endif
     814             :     }
     815             : #endif
     816             :     return ptr + 2 * sizeof(void *);
     817             : #else
     818    21459100 :     return realloc(pData, nNewSize);
     819             : #endif
     820             : }
     821             : 
     822             : /************************************************************************/
     823             : /*                              VSIFree()                               */
     824             : /************************************************************************/
     825             : 
     826             : /** Analog of free() for data allocated with VSIMalloc(), VSICalloc(),
     827             :  * VSIRealloc() */
     828   134065000 : void VSIFree(void *pData)
     829             : 
     830             : {
     831             : #ifdef DEBUG_VSIMALLOC
     832             :     if (pData == nullptr)
     833             :         return;
     834             : 
     835             :     char *ptr = ((char *)pData) - 2 * sizeof(void *);
     836             :     VSICheckMarkerBegin(ptr);
     837             :     size_t nOldSize = 0;
     838             :     // cppcheck-suppress pointerSize
     839             :     memcpy(&nOldSize, ptr + sizeof(void *), sizeof(void *));
     840             :     VSICheckMarkerEnd(ptr, 2 * sizeof(void *) + nOldSize);
     841             :     ptr[0] = 'M';
     842             :     ptr[1] = 'I';
     843             :     ptr[2] = 'S';
     844             :     ptr[3] = 'V';
     845             :     ptr[2 * sizeof(void *) + nOldSize + 0] = 'I';
     846             :     ptr[2 * sizeof(void *) + nOldSize + 1] = 'S';
     847             :     ptr[2 * sizeof(void *) + nOldSize + 2] = 'V';
     848             :     ptr[2 * sizeof(void *) + nOldSize + 3] = 'E';
     849             : #if defined(DEBUG_VSIMALLOC_STATS) || defined(DEBUG_VSIMALLOC_VERBOSE)
     850             :     {
     851             :         CPLMutexHolderD(&hMemStatMutex);
     852             : #ifdef DEBUG_VSIMALLOC_VERBOSE
     853             :         if (nOldSize > THRESHOLD_PRINT)
     854             :         {
     855             :             fprintf(stderr, "Thread[%p] VSIFree(%p, (%d bytes))\n", /*ok*/
     856             :                     (void *)CPLGetPID(), pData, static_cast<int>(nOldSize));
     857             :         }
     858             : #endif
     859             : #ifdef DEBUG_VSIMALLOC_STATS
     860             :         nVSIFrees++;
     861             :         nCurrentTotalAllocs -= nOldSize;
     862             : #endif
     863             :     }
     864             : #endif
     865             : 
     866             : #ifdef DEBUG_VSIMALLOC_MPROTECT
     867             :     mprotect(ptr, nOldSize + 2 * sizeof(void *), PROT_NONE);
     868             : #else
     869             :     free(ptr);
     870             : #endif
     871             : 
     872             : #else
     873   134065000 :     if (pData != nullptr)
     874   113040000 :         free(pData);
     875             : #endif
     876   134065000 : }
     877             : 
     878             : /************************************************************************/
     879             : /*                      VSIMallocAligned()                              */
     880             : /************************************************************************/
     881             : 
     882             : /** Allocates a buffer with an alignment constraint.
     883             :  *
     884             :  * The return value must be freed with VSIFreeAligned().
     885             :  *
     886             :  * @param nAlignment Must be a power of 2, multiple of sizeof(void*), and
     887             :  *                   lesser than 256.
     888             :  * @param nSize Size of the buffer to allocate.
     889             :  * @return a buffer aligned on nAlignment and of size nSize, or NULL
     890             :  * @since GDAL 2.2
     891             :  */
     892             : 
     893     3160800 : void *VSIMallocAligned(size_t nAlignment, size_t nSize)
     894             : {
     895             :     // In particular for posix_memalign() where behavior when passing
     896             :     // nSize == 0 is technically implementation defined (Valgrind complains),
     897             :     // so let's always return NULL.
     898     3160800 :     if (nSize == 0)
     899           0 :         return nullptr;
     900             : #if defined(HAVE_POSIX_MEMALIGN) && !defined(DEBUG_VSIMALLOC)
     901     3160800 :     void *pRet = nullptr;
     902     3160800 :     if (posix_memalign(&pRet, nAlignment, nSize) != 0)
     903             :     {
     904           4 :         pRet = nullptr;
     905             :     }
     906     3160800 :     return pRet;
     907             : #elif defined(_WIN32) && !defined(DEBUG_VSIMALLOC)
     908             :     return _aligned_malloc(nSize, nAlignment);
     909             : #else
     910             :     // Check constraints on alignment.
     911             :     if (nAlignment < sizeof(void *) || nAlignment >= 256 ||
     912             :         (nAlignment & (nAlignment - 1)) != 0)
     913             :         return nullptr;
     914             :     // Detect overflow.
     915             :     if (nSize + nAlignment < nSize)
     916             :         return nullptr;
     917             :     GByte *pabyData = static_cast<GByte *>(VSIMalloc(nSize + nAlignment));
     918             :     if (pabyData == nullptr)
     919             :         return nullptr;
     920             :     size_t nShift =
     921             :         nAlignment - (reinterpret_cast<size_t>(pabyData) % nAlignment);
     922             :     GByte *pabyAligned = pabyData + nShift;
     923             :     // Guaranteed to fit on a byte since nAlignment < 256.
     924             :     pabyAligned[-1] = static_cast<GByte>(nShift);
     925             :     return pabyAligned;
     926             : #endif
     927             : }
     928             : 
     929             : /************************************************************************/
     930             : /*                     VSIMallocAlignedAuto()                           */
     931             : /************************************************************************/
     932             : 
     933             : /** Allocates a buffer with an alignment constraint such that it can be
     934             :  * used by the most demanding vector instruction set on that platform.
     935             :  *
     936             :  * The return value must be freed with VSIFreeAligned().
     937             :  *
     938             :  * @param nSize Size of the buffer to allocate.
     939             :  * @return an aligned buffer of size nSize, or NULL
     940             :  * @since GDAL 2.2
     941             :  */
     942             : 
     943     3160780 : void *VSIMallocAlignedAuto(size_t nSize)
     944             : {
     945             :     // We could potentially dynamically detect the capability of the CPU
     946             :     // but to simplify use 64 for AVX512 requirements (we use only AVX256
     947             :     // currently).
     948     3160780 :     return VSIMallocAligned(64, nSize);
     949             : }
     950             : 
     951             : /************************************************************************/
     952             : /*                        VSIMallocAlignedAutoVerbose()                 */
     953             : /************************************************************************/
     954             : 
     955             : /** See VSIMallocAlignedAuto() */
     956     3160780 : void *VSIMallocAlignedAutoVerbose(size_t nSize, const char *pszFile, int nLine)
     957             : {
     958     3160780 :     void *pRet = VSIMallocAlignedAuto(nSize);
     959     3160770 :     if (pRet == nullptr && nSize != 0)
     960             :     {
     961           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
     962             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB " bytes",
     963             :                  pszFile ? pszFile : "(unknown file)", nLine,
     964             :                  static_cast<GUIntBig>(nSize));
     965             :     }
     966     3160750 :     return pRet;
     967             : }
     968             : 
     969             : /************************************************************************/
     970             : /*                        VSIFreeAligned()                              */
     971             : /************************************************************************/
     972             : 
     973             : /** Free a buffer allocated with VSIMallocAligned().
     974             :  *
     975             :  * @param ptr Buffer to free.
     976             :  * @since GDAL 2.2
     977             :  */
     978             : 
     979     3183110 : void VSIFreeAligned(void *ptr)
     980             : {
     981             : #if defined(HAVE_POSIX_MEMALIGN) && !defined(DEBUG_VSIMALLOC)
     982     3183110 :     free(ptr);
     983             : #elif defined(_WIN32) && !defined(DEBUG_VSIMALLOC)
     984             :     _aligned_free(ptr);
     985             : #else
     986             :     if (ptr == nullptr)
     987             :         return;
     988             :     GByte *pabyAligned = static_cast<GByte *>(ptr);
     989             :     size_t nShift = pabyAligned[-1];
     990             :     VSIFree(pabyAligned - nShift);
     991             : #endif
     992     3183110 : }
     993             : 
     994             : /************************************************************************/
     995             : /*                             VSIStrdup()                              */
     996             : /************************************************************************/
     997             : 
     998             : /** Analog of strdup(). Use VSIFree() to free */
     999    32816300 : char *VSIStrdup(const char *pszString)
    1000             : 
    1001             : {
    1002    32816300 :     const size_t nSize = strlen(pszString) + 1;
    1003    32816300 :     char *ptr = static_cast<char *>(VSIMalloc(nSize));
    1004    32816200 :     if (ptr == nullptr)
    1005           0 :         return nullptr;
    1006    32816200 :     memcpy(ptr, pszString, nSize);
    1007    32816200 :     return ptr;
    1008             : }
    1009             : 
    1010             : /************************************************************************/
    1011             : /*                          VSICheckMul2()                              */
    1012             : /************************************************************************/
    1013             : 
    1014             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    1015      277256 : static size_t VSICheckMul2(size_t mul1, size_t mul2, bool *pbOverflowFlag,
    1016             :                            const char *pszFile, int nLine)
    1017             : {
    1018      277256 :     const size_t res = mul1 * mul2;
    1019      277256 :     if (mul1 != 0)
    1020             :     {
    1021      277247 :         if (res / mul1 == mul2)
    1022             :         {
    1023      277247 :             if (pbOverflowFlag)
    1024      277246 :                 *pbOverflowFlag = FALSE;
    1025      277247 :             return res;
    1026             :         }
    1027             :         else
    1028             :         {
    1029           0 :             if (pbOverflowFlag)
    1030           1 :                 *pbOverflowFlag = TRUE;
    1031           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1032             :                      "%s: %d: Multiplication overflow : " CPL_FRMT_GUIB
    1033             :                      " * " CPL_FRMT_GUIB,
    1034             :                      pszFile ? pszFile : "(unknown file)", nLine,
    1035             :                      static_cast<GUIntBig>(mul1), static_cast<GUIntBig>(mul2));
    1036             :         }
    1037             :     }
    1038             :     else
    1039             :     {
    1040           9 :         if (pbOverflowFlag)
    1041           8 :             *pbOverflowFlag = FALSE;
    1042             :     }
    1043           9 :     return 0;
    1044             : }
    1045             : 
    1046             : /************************************************************************/
    1047             : /*                          VSICheckMul3()                              */
    1048             : /************************************************************************/
    1049             : 
    1050             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    1051       95939 : static size_t VSICheckMul3(size_t mul1, size_t mul2, size_t mul3,
    1052             :                            bool *pbOverflowFlag, const char *pszFile, int nLine)
    1053             : {
    1054       95939 :     if (mul1 != 0)
    1055             :     {
    1056       95934 :         const size_t res = mul1 * mul2;
    1057       95934 :         if (res / mul1 == mul2)
    1058             :         {
    1059       95923 :             const size_t res2 = res * mul3;
    1060       95923 :             if (mul3 != 0)
    1061             :             {
    1062       95928 :                 if (res2 / mul3 == res)
    1063             :                 {
    1064       95922 :                     if (pbOverflowFlag)
    1065       95926 :                         *pbOverflowFlag = false;
    1066       95922 :                     return res2;
    1067             :                 }
    1068             :                 else
    1069             :                 {
    1070           6 :                     if (pbOverflowFlag)
    1071           2 :                         *pbOverflowFlag = true;
    1072           6 :                     CPLError(CE_Failure, CPLE_OutOfMemory,
    1073             :                              "%s: %d: Multiplication overflow : " CPL_FRMT_GUIB
    1074             :                              " * " CPL_FRMT_GUIB " * " CPL_FRMT_GUIB,
    1075             :                              pszFile ? pszFile : "(unknown file)", nLine,
    1076             :                              static_cast<GUIntBig>(mul1),
    1077             :                              static_cast<GUIntBig>(mul2),
    1078             :                              static_cast<GUIntBig>(mul3));
    1079             :                 }
    1080             :             }
    1081             :             else
    1082             :             {
    1083           0 :                 if (pbOverflowFlag)
    1084           1 :                     *pbOverflowFlag = false;
    1085             :             }
    1086             :         }
    1087             :         else
    1088             :         {
    1089          11 :             if (pbOverflowFlag)
    1090           1 :                 *pbOverflowFlag = true;
    1091          11 :             CPLError(CE_Failure, CPLE_OutOfMemory,
    1092             :                      "%s: %d: Multiplication overflow : " CPL_FRMT_GUIB
    1093             :                      " * " CPL_FRMT_GUIB " * " CPL_FRMT_GUIB,
    1094             :                      pszFile ? pszFile : "(unknown file)", nLine,
    1095             :                      static_cast<GUIntBig>(mul1), static_cast<GUIntBig>(mul2),
    1096             :                      static_cast<GUIntBig>(mul3));
    1097             :         }
    1098             :     }
    1099             :     else
    1100             :     {
    1101           5 :         if (pbOverflowFlag)
    1102           1 :             *pbOverflowFlag = false;
    1103             :     }
    1104           5 :     return 0;
    1105             : }
    1106             : 
    1107             : /**
    1108             :  VSIMalloc2 allocates (nSize1 * nSize2) bytes.
    1109             :  In case of overflow of the multiplication, or if memory allocation fails, a
    1110             :  NULL pointer is returned and a CE_Failure error is raised with CPLError().
    1111             :  If nSize1 == 0 || nSize2 == 0, a NULL pointer will also be returned.
    1112             :  CPLFree() or VSIFree() can be used to free memory allocated by this function.
    1113             : */
    1114         153 : void CPL_DLL *VSIMalloc2(size_t nSize1, size_t nSize2)
    1115             : {
    1116         153 :     return VSIMalloc2Verbose(nSize1, nSize2, nullptr, 0);
    1117             : }
    1118             : 
    1119             : /**
    1120             :  VSIMalloc3 allocates (nSize1 * nSize2 * nSize3) bytes.
    1121             :  In case of overflow of the multiplication, or if memory allocation fails, a
    1122             :  NULL pointer is returned and a CE_Failure error is raised with CPLError().
    1123             :  If nSize1 == 0 || nSize2 == 0 || nSize3 == 0, a NULL pointer will also be
    1124             :  returned.  CPLFree() or VSIFree() can be used to free memory allocated by this
    1125             :  function.
    1126             : */
    1127         815 : void CPL_DLL *VSIMalloc3(size_t nSize1, size_t nSize2, size_t nSize3)
    1128             : {
    1129         815 :     return VSIMalloc3Verbose(nSize1, nSize2, nSize3, nullptr, 0);
    1130             : }
    1131             : 
    1132             : /************************************************************************/
    1133             : /*                          VSIMallocVerbose()                          */
    1134             : /************************************************************************/
    1135             : 
    1136     7244020 : void *VSIMallocVerbose(size_t nSize, const char *pszFile, int nLine)
    1137             : {
    1138     7244020 :     void *pRet = VSIMalloc(nSize);
    1139     7244050 :     if (pRet == nullptr && nSize != 0)
    1140             :     {
    1141           2 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1142             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB " bytes",
    1143             :                  pszFile ? pszFile : "(unknown file)", nLine,
    1144             :                  static_cast<GUIntBig>(nSize));
    1145             :     }
    1146     7243980 :     return pRet;
    1147             : }
    1148             : 
    1149             : /************************************************************************/
    1150             : /*                          VSIMalloc2Verbose()                         */
    1151             : /************************************************************************/
    1152             : 
    1153      277256 : void *VSIMalloc2Verbose(size_t nSize1, size_t nSize2, const char *pszFile,
    1154             :                         int nLine)
    1155             : {
    1156      277256 :     bool bOverflowFlag = false;
    1157             :     const size_t nSizeToAllocate =
    1158      277256 :         VSICheckMul2(nSize1, nSize2, &bOverflowFlag, pszFile, nLine);
    1159      277257 :     if (bOverflowFlag || nSizeToAllocate == 0)
    1160          39 :         return nullptr;
    1161             : 
    1162      277218 :     void *pRet = VSIMalloc(nSizeToAllocate);
    1163      277228 :     if (pRet == nullptr)
    1164             :     {
    1165           2 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1166             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB " bytes",
    1167             :                  pszFile ? pszFile : "(unknown file)", nLine,
    1168             :                  static_cast<GUIntBig>(nSize1) * static_cast<GUIntBig>(nSize2));
    1169             :     }
    1170      277227 :     return pRet;
    1171             : }
    1172             : 
    1173             : /************************************************************************/
    1174             : /*                          VSIMalloc3Verbose()                         */
    1175             : /************************************************************************/
    1176             : 
    1177       95931 : void *VSIMalloc3Verbose(size_t nSize1, size_t nSize2, size_t nSize3,
    1178             :                         const char *pszFile, int nLine)
    1179             : {
    1180       95931 :     bool bOverflowFlag = false;
    1181             :     size_t nSizeToAllocate =
    1182       95931 :         VSICheckMul3(nSize1, nSize2, nSize3, &bOverflowFlag, pszFile, nLine);
    1183       95916 :     if (bOverflowFlag || nSizeToAllocate == 0)
    1184           8 :         return nullptr;
    1185             : 
    1186       95908 :     void *pRet = VSIMalloc(nSizeToAllocate);
    1187       95943 :     if (pRet == nullptr)
    1188             :     {
    1189           4 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1190             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB " bytes",
    1191             :                  pszFile ? pszFile : "(unknown file)", nLine,
    1192           4 :                  static_cast<GUIntBig>(nSize1) * static_cast<GUIntBig>(nSize2) *
    1193             :                      static_cast<GUIntBig>(nSize3));
    1194             :     }
    1195       95944 :     return pRet;
    1196             : }
    1197             : 
    1198             : /************************************************************************/
    1199             : /*                          VSICallocVerbose()                          */
    1200             : /************************************************************************/
    1201             : 
    1202     8879140 : void *VSICallocVerbose(size_t nCount, size_t nSize, const char *pszFile,
    1203             :                        int nLine)
    1204             : {
    1205     8879140 :     void *pRet = VSICalloc(nCount, nSize);
    1206     8879170 :     if (pRet == nullptr && nCount != 0 && nSize != 0)
    1207             :     {
    1208           4 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1209             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB "x" CPL_FRMT_GUIB
    1210             :                  " bytes",
    1211             :                  pszFile ? pszFile : "(unknown file)", nLine,
    1212             :                  static_cast<GUIntBig>(nCount), static_cast<GUIntBig>(nSize));
    1213             :     }
    1214     8879180 :     return pRet;
    1215             : }
    1216             : 
    1217             : /************************************************************************/
    1218             : /*                          VSIReallocVerbose()                         */
    1219             : /************************************************************************/
    1220             : 
    1221    17166900 : void *VSIReallocVerbose(void *pOldPtr, size_t nNewSize, const char *pszFile,
    1222             :                         int nLine)
    1223             : {
    1224    17166900 :     void *pRet = VSIRealloc(pOldPtr, nNewSize);
    1225    17166900 :     if (pRet == nullptr && nNewSize != 0)
    1226             :     {
    1227           2 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1228             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB " bytes",
    1229             :                  pszFile ? pszFile : "(unknown file)", nLine,
    1230             :                  static_cast<GUIntBig>(nNewSize));
    1231             :     }
    1232    17166900 :     return pRet;
    1233             : }
    1234             : 
    1235             : /************************************************************************/
    1236             : /*                          VSIStrdupVerbose()                          */
    1237             : /************************************************************************/
    1238             : 
    1239    10174200 : char *VSIStrdupVerbose(const char *pszStr, const char *pszFile, int nLine)
    1240             : {
    1241    10174200 :     char *pRet = VSIStrdup(pszStr);
    1242    10174100 :     if (pRet == nullptr)
    1243             :     {
    1244           0 :         CPLError(CE_Failure, CPLE_OutOfMemory,
    1245             :                  "%s, %d: cannot allocate " CPL_FRMT_GUIB " bytes",
    1246             :                  pszFile ? pszFile : "(unknown file)", nLine,
    1247           0 :                  static_cast<GUIntBig>(strlen(pszStr) + 1));
    1248             :     }
    1249    10174100 :     return pRet;
    1250             : }
    1251             : 
    1252             : /************************************************************************/
    1253             : /*                              VSIStat()                               */
    1254             : /************************************************************************/
    1255             : 
    1256         974 : int VSIStat(const char *pszFilename, VSIStatBuf *pStatBuf)
    1257             : 
    1258             : {
    1259             : #if defined(_WIN32)
    1260             :     if (CPLTestBool(CPLGetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")))
    1261             :     {
    1262             :         wchar_t *pwszFilename =
    1263             :             CPLRecodeToWChar(pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2);
    1264             : 
    1265             :         int nResult =
    1266             :             _wstat(pwszFilename, reinterpret_cast<struct _stat *>(pStatBuf));
    1267             : 
    1268             :         CPLFree(pwszFilename);
    1269             : 
    1270             :         return nResult;
    1271             :     }
    1272             : 
    1273             : #endif
    1274         974 :     return stat(pszFilename, pStatBuf);
    1275             : }
    1276             : 
    1277             : /************************************************************************/
    1278             : /*                              VSITime()                               */
    1279             : /************************************************************************/
    1280             : 
    1281           0 : unsigned long VSITime(unsigned long *pnTimeToSet)
    1282             : 
    1283             : {
    1284             :     time_t tTime;
    1285             : 
    1286           0 :     tTime = time(nullptr);
    1287             : 
    1288           0 :     if (pnTimeToSet != nullptr)
    1289           0 :         *pnTimeToSet = static_cast<unsigned long>(tTime);
    1290             : 
    1291           0 :     return static_cast<unsigned long>(tTime);
    1292             : }
    1293             : 
    1294             : /************************************************************************/
    1295             : /*                              VSICTime()                              */
    1296             : /************************************************************************/
    1297             : 
    1298           4 : const char *VSICTime(unsigned long nTime)
    1299             : 
    1300             : {
    1301           4 :     time_t tTime = static_cast<time_t>(nTime);
    1302             : #if HAVE_CTIME_R
    1303             :     // Cf https://linux.die.net/man/3/ctime_r:
    1304             :     // "The reentrant version ctime_r() does the same, but stores the string in
    1305             :     // a user-supplied buffer which should have room for at least 26 bytes"
    1306             :     char buffer[26];
    1307           4 :     char *ret = ctime_r(&tTime, buffer);
    1308           4 :     return ret ? CPLSPrintf("%s", ret) : nullptr;
    1309             : #elif defined(_WIN32)
    1310             :     char buffer[26];
    1311             :     return ctime_s(buffer, sizeof(buffer), &tTime) == 0
    1312             :                ? CPLSPrintf("%s", buffer)
    1313             :                : nullptr;
    1314             : #else
    1315             :     return reinterpret_cast<const char *>(ctime(&tTime));
    1316             : #endif
    1317             : }
    1318             : 
    1319             : /************************************************************************/
    1320             : /*                             VSIGMTime()                              */
    1321             : /************************************************************************/
    1322             : 
    1323           0 : struct tm *VSIGMTime(const time_t *pnTime, struct tm *poBrokenTime)
    1324             : {
    1325             : 
    1326             : #if HAVE_GMTIME_R
    1327           0 :     gmtime_r(pnTime, poBrokenTime);
    1328           0 :     return poBrokenTime;
    1329             : #elif defined(_WIN32)
    1330             :     return gmtime_s(poBrokenTime, pnTime) == 0 ? poBrokenTime : nullptr;
    1331             : #else
    1332             :     struct tm *poTime = gmtime(pnTime);
    1333             :     memcpy(poBrokenTime, poTime, sizeof(tm));
    1334             :     return poBrokenTime;
    1335             : #endif
    1336             : }
    1337             : 
    1338             : /************************************************************************/
    1339             : /*                             VSILocalTime()                           */
    1340             : /************************************************************************/
    1341             : 
    1342         527 : struct tm *VSILocalTime(const time_t *pnTime, struct tm *poBrokenTime)
    1343             : {
    1344             : 
    1345             : #if HAVE_LOCALTIME_R
    1346         527 :     localtime_r(pnTime, poBrokenTime);
    1347         527 :     return poBrokenTime;
    1348             : #elif defined(_WIN32)
    1349             :     return localtime_s(poBrokenTime, pnTime) == 0 ? poBrokenTime : nullptr;
    1350             : #else
    1351             :     struct tm *poTime = localtime(pnTime);
    1352             :     memcpy(poBrokenTime, poTime, sizeof(tm));
    1353             :     return poBrokenTime;
    1354             : #endif
    1355             : }
    1356             : 
    1357             : /************************************************************************/
    1358             : /*                            VSIStrerror()                             */
    1359             : /************************************************************************/
    1360             : 
    1361             : /** Return the error string corresponding to the error number. Do not free it */
    1362         150 : char *VSIStrerror(int nErrno)
    1363             : 
    1364             : {
    1365         150 :     return strerror(nErrno);
    1366             : }
    1367             : 
    1368             : /************************************************************************/
    1369             : /*                        CPLGetPhysicalRAM()                           */
    1370             : /************************************************************************/
    1371             : 
    1372             : #if HAVE_SC_PHYS_PAGES
    1373             : 
    1374             : /** Return the total physical RAM in bytes.
    1375             :  *
    1376             :  * In the context of a container using cgroups (typically Docker), this
    1377             :  * will take into account that limitation (starting with GDAL 2.4.0 and
    1378             :  * with extra fixes in GDAL 3.6.3)
    1379             :  *
    1380             :  * You should generally use CPLGetUsablePhysicalRAM() instead.
    1381             :  *
    1382             :  * @return the total physical RAM in bytes (or 0 in case of failure).
    1383             :  * @since GDAL 2.0
    1384             :  */
    1385        5775 : GIntBig CPLGetPhysicalRAM(void)
    1386             : {
    1387        5775 :     const long nPhysPages = sysconf(_SC_PHYS_PAGES);
    1388        5775 :     const long nPageSize = sysconf(_SC_PAGESIZE);
    1389       11550 :     if (nPhysPages <= 0 || nPageSize <= 0 ||
    1390        5775 :         nPhysPages > std::numeric_limits<GIntBig>::max() / nPageSize)
    1391             :     {
    1392           0 :         return 0;
    1393             :     }
    1394        5775 :     GIntBig nVal = static_cast<GIntBig>(nPhysPages) * nPageSize;
    1395             : 
    1396             : #ifdef __linux
    1397             :     {
    1398             :         // Take into account MemTotal in /proc/meminfo
    1399             :         // which seems to be necessary for some container solutions
    1400             :         // Cf https://lists.osgeo.org/pipermail/gdal-dev/2023-January/056784.html
    1401        5775 :         FILE *f = fopen("/proc/meminfo", "rb");
    1402             :         char szLine[256];
    1403        5775 :         while (fgets(szLine, sizeof(szLine), f))
    1404             :         {
    1405             :             // Find line like "MemTotal:       32525176 kB"
    1406        5775 :             if (strncmp(szLine, "MemTotal:", strlen("MemTotal:")) == 0)
    1407             :             {
    1408        5775 :                 char *pszVal = szLine + strlen("MemTotal:");
    1409        5775 :                 pszVal += strspn(pszVal, " ");
    1410        5775 :                 char *pszEnd = strstr(pszVal, " kB");
    1411        5775 :                 if (pszEnd)
    1412             :                 {
    1413        5775 :                     *pszEnd = 0;
    1414        5775 :                     if (CPLGetValueType(pszVal) == CPL_VALUE_INTEGER)
    1415             :                     {
    1416             :                         const GUIntBig nLimit =
    1417       11550 :                             CPLScanUIntBig(pszVal,
    1418        5775 :                                            static_cast<int>(strlen(pszVal))) *
    1419        5775 :                             1024;
    1420        5775 :                         nVal = static_cast<GIntBig>(
    1421        5775 :                             std::min(static_cast<GUIntBig>(nVal), nLimit));
    1422             :                     }
    1423             :                 }
    1424        5775 :                 break;
    1425             :             }
    1426             :         }
    1427        5775 :         fclose(f);
    1428             :     }
    1429             : 
    1430             :     char szGroupName[256];
    1431        5775 :     bool bFromMemory = false;
    1432        5775 :     szGroupName[0] = 0;
    1433             :     {
    1434        5775 :         FILE *f = fopen("/proc/self/cgroup", "rb");
    1435             :         char szLine[256];
    1436             :         // Find line like "6:memory:/user.slice/user-1000.slice/user@1000.service"
    1437             :         // and store "/user.slice/user-1000.slice/user@1000.service" in
    1438             :         // szMemoryPath for cgroup V1 or single line "0::/...." for cgroup V2.
    1439        5775 :         while (fgets(szLine, sizeof(szLine), f))
    1440             :         {
    1441        5775 :             const char *pszMemory = strstr(szLine, ":memory:");
    1442        5775 :             if (pszMemory)
    1443             :             {
    1444           0 :                 bFromMemory = true;
    1445           0 :                 snprintf(szGroupName, sizeof(szGroupName), "%s",
    1446             :                          pszMemory + strlen(":memory:"));
    1447           0 :                 char *pszEOL = strchr(szGroupName, '\n');
    1448           0 :                 if (pszEOL)
    1449           0 :                     *pszEOL = '\0';
    1450           0 :                 break;
    1451             :             }
    1452        5775 :             if (strncmp(szLine, "0::", strlen("0::")) == 0)
    1453             :             {
    1454        5775 :                 snprintf(szGroupName, sizeof(szGroupName), "%s",
    1455             :                          szLine + strlen("0::"));
    1456        5775 :                 char *pszEOL = strchr(szGroupName, '\n');
    1457        5775 :                 if (pszEOL)
    1458        5775 :                     *pszEOL = '\0';
    1459        5775 :                 break;
    1460             :             }
    1461             :         }
    1462        5775 :         fclose(f);
    1463             :     }
    1464        5775 :     if (szGroupName[0])
    1465             :     {
    1466             :         char szFilename[256 + 64];
    1467        5775 :         if (bFromMemory)
    1468             :         {
    1469             :             // cgroup V1
    1470             :             // Read memory.limit_in_byte in the whole szGroupName hierarchy
    1471             :             // Make sure to end up by reading
    1472             :             // /sys/fs/cgroup/memory/memory.limit_in_bytes itself, for
    1473             :             // scenarios like https://github.com/OSGeo/gdal/issues/8968
    1474             :             while (true)
    1475             :             {
    1476           0 :                 snprintf(szFilename, sizeof(szFilename),
    1477             :                          "/sys/fs/cgroup/memory/%s/memory.limit_in_bytes",
    1478             :                          szGroupName);
    1479           0 :                 FILE *f = fopen(szFilename, "rb");
    1480           0 :                 if (f)
    1481             :                 {
    1482             :                     // If no limitation, on 64 bit, 9223372036854771712 is returned.
    1483             :                     char szBuffer[32];
    1484             :                     const int nRead = static_cast<int>(
    1485           0 :                         fread(szBuffer, 1, sizeof(szBuffer) - 1, f));
    1486           0 :                     szBuffer[nRead] = 0;
    1487           0 :                     fclose(f);
    1488           0 :                     const GUIntBig nLimit = CPLScanUIntBig(szBuffer, nRead);
    1489           0 :                     nVal = static_cast<GIntBig>(
    1490           0 :                         std::min(static_cast<GUIntBig>(nVal), nLimit));
    1491             :                 }
    1492           0 :                 char *pszLastSlash = strrchr(szGroupName, '/');
    1493           0 :                 if (!pszLastSlash)
    1494           0 :                     break;
    1495           0 :                 *pszLastSlash = '\0';
    1496           0 :             }
    1497             :         }
    1498             :         else
    1499             :         {
    1500             :             // cgroup V2
    1501             :             // Read memory.max in the whole szGroupName hierarchy
    1502             :             while (true)
    1503             :             {
    1504        5775 :                 snprintf(szFilename, sizeof(szFilename),
    1505             :                          "/sys/fs/cgroup/%s/memory.max", szGroupName);
    1506        5775 :                 FILE *f = fopen(szFilename, "rb");
    1507        5775 :                 if (f)
    1508             :                 {
    1509             :                     // If no limitation, "max" is returned.
    1510             :                     char szBuffer[32];
    1511             :                     int nRead = static_cast<int>(
    1512        5775 :                         fread(szBuffer, 1, sizeof(szBuffer) - 1, f));
    1513        5775 :                     szBuffer[nRead] = 0;
    1514        5775 :                     if (nRead > 0 && szBuffer[nRead - 1] == '\n')
    1515             :                     {
    1516        5775 :                         nRead--;
    1517        5775 :                         szBuffer[nRead] = 0;
    1518             :                     }
    1519        5775 :                     fclose(f);
    1520        5775 :                     if (CPLGetValueType(szBuffer) == CPL_VALUE_INTEGER)
    1521             :                     {
    1522           0 :                         const GUIntBig nLimit = CPLScanUIntBig(szBuffer, nRead);
    1523           0 :                         nVal = static_cast<GIntBig>(
    1524           0 :                             std::min(static_cast<GUIntBig>(nVal), nLimit));
    1525             :                     }
    1526             :                 }
    1527        5775 :                 char *pszLastSlash = strrchr(szGroupName, '/');
    1528        5775 :                 if (!pszLastSlash || pszLastSlash == szGroupName)
    1529             :                     break;
    1530           0 :                 *pszLastSlash = '\0';
    1531           0 :             }
    1532             :         }
    1533             :     }
    1534             : #endif
    1535             : 
    1536        5775 :     return nVal;
    1537             : }
    1538             : 
    1539             : #elif defined(__MACH__) && defined(__APPLE__)
    1540             : 
    1541             : #include <sys/types.h>
    1542             : #include <sys/sysctl.h>
    1543             : 
    1544             : GIntBig CPLGetPhysicalRAM(void)
    1545             : {
    1546             :     GIntBig nPhysMem = 0;
    1547             : 
    1548             :     int mib[2] = {CTL_HW, HW_MEMSIZE};
    1549             :     size_t nLengthRes = sizeof(nPhysMem);
    1550             :     sysctl(mib, CPL_ARRAYSIZE(mib), &nPhysMem, &nLengthRes, nullptr, 0);
    1551             : 
    1552             :     return nPhysMem;
    1553             : }
    1554             : 
    1555             : #elif defined(_WIN32)
    1556             : 
    1557             : // GlobalMemoryStatusEx requires _WIN32_WINNT >= 0x0500.
    1558             : #ifndef _WIN32_WINNT
    1559             : #define _WIN32_WINNT 0x0500
    1560             : #endif
    1561             : #include <windows.h>
    1562             : 
    1563             : GIntBig CPLGetPhysicalRAM(void)
    1564             : {
    1565             :     MEMORYSTATUSEX statex;
    1566             :     statex.ullTotalPhys = 0;
    1567             :     statex.dwLength = sizeof(statex);
    1568             :     GlobalMemoryStatusEx(&statex);
    1569             :     return static_cast<GIntBig>(statex.ullTotalPhys);
    1570             : }
    1571             : 
    1572             : #else
    1573             : 
    1574             : GIntBig CPLGetPhysicalRAM(void)
    1575             : {
    1576             :     static bool bOnce = false;
    1577             :     if (!bOnce)
    1578             :     {
    1579             :         bOnce = true;
    1580             :         CPLDebug("PORT", "No implementation for CPLGetPhysicalRAM()");
    1581             :     }
    1582             :     return 0;
    1583             : }
    1584             : #endif
    1585             : 
    1586             : /************************************************************************/
    1587             : /*                       CPLGetUsablePhysicalRAM()                      */
    1588             : /************************************************************************/
    1589             : 
    1590             : /** Return the total physical RAM, usable by a process, in bytes.
    1591             :  *
    1592             :  * This is the same as CPLGetPhysicalRAM() except it will limit to 2 GB
    1593             :  * for 32 bit processes.
    1594             :  *
    1595             :  * Starting with GDAL 2.4.0, it will also take account resource limits (virtual
    1596             :  * memory) on Posix systems. Starting with GDAL 3.6.1, it will also take into
    1597             :  * account RLIMIT_RSS on Linux.
    1598             :  *
    1599             :  * Note: This memory may already be partly used by other processes.
    1600             :  *
    1601             :  * @return the total physical RAM, usable by a process, in bytes (or 0
    1602             :  * in case of failure).
    1603             :  * @since GDAL 2.0
    1604             :  */
    1605        5774 : GIntBig CPLGetUsablePhysicalRAM(void)
    1606             : {
    1607        5774 :     GIntBig nRAM = CPLGetPhysicalRAM();
    1608             : #if SIZEOF_VOIDP == 4
    1609             :     if (nRAM > INT_MAX)
    1610             :         nRAM = INT_MAX;
    1611             : #endif
    1612             : #if HAVE_GETRLIMIT
    1613             :     struct rlimit sLimit;
    1614             : #if HAVE_RLIMIT_AS
    1615        5774 :     const int res = RLIMIT_AS;
    1616             : #else
    1617             :     // OpenBSD currently doesn't support RLIMIT_AS (mandated by Posix though)
    1618             :     const int res = RLIMIT_DATA;
    1619             : #endif
    1620        5774 :     if (getrlimit(res, &sLimit) == 0 && sLimit.rlim_cur != RLIM_INFINITY &&
    1621           0 :         static_cast<GIntBig>(sLimit.rlim_cur) < nRAM)
    1622             :     {
    1623           0 :         nRAM = static_cast<GIntBig>(sLimit.rlim_cur);
    1624             :     }
    1625             : #ifdef RLIMIT_RSS
    1626             :     // Helps with RSS limit set by the srun utility. Cf
    1627             :     // https://github.com/OSGeo/gdal/issues/6669
    1628        5774 :     if (getrlimit(RLIMIT_RSS, &sLimit) == 0 &&
    1629        5774 :         sLimit.rlim_cur != RLIM_INFINITY &&
    1630           0 :         static_cast<GIntBig>(sLimit.rlim_cur) < nRAM)
    1631             :     {
    1632           0 :         nRAM = static_cast<GIntBig>(sLimit.rlim_cur);
    1633             :     }
    1634             : #endif
    1635             : #endif
    1636        5774 :     return nRAM;
    1637             : }

Generated by: LCOV version 1.14