Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDALGetCacheMax64(): fix TSAN complaint (fixes #1837) #9253

Merged
merged 2 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 59 additions & 57 deletions gcore/gdalrasterblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <algorithm>
#include <climits>
#include <cstring>
#include <mutex>

#include "cpl_atomic_ops.h"
#include "cpl_conv.h"
Expand All @@ -43,7 +44,6 @@
#include "cpl_string.h"
#include "cpl_vsi.h"

static bool bCacheMaxInitialized = false;
// Will later be overridden by the default 5% if GDAL_CACHEMAX not defined.
static GIntBig nCacheMax = 40 * 1024 * 1024;
static GIntBig nCacheUsed = 0;
Expand Down Expand Up @@ -153,10 +153,8 @@ void CPL_STDCALL GDALSetCacheMax64(GIntBig nNewSizeInBytes)
}
#endif

{
INITIALIZE_LOCK;
}
bCacheMaxInitialized = true;
// To force one-time initialization of nCacheMax if not already done
GDALGetCacheMax64();
nCacheMax = nNewSizeInBytes;

/* -------------------------------------------------------------------- */
Expand Down Expand Up @@ -237,73 +235,77 @@ int CPL_STDCALL GDALGetCacheMax()

GIntBig CPL_STDCALL GDALGetCacheMax64()
{
if (!bCacheMaxInitialized)
{
static std::once_flag flagSetupGDALGetCacheMax64;
std::call_once(
flagSetupGDALGetCacheMax64,
[]()
{
INITIALIZE_LOCK;
}
bSleepsForBockCacheDebug =
CPLTestBool(CPLGetConfigOption("GDAL_DEBUG_BLOCK_CACHE", "NO"));
{
INITIALIZE_LOCK;
}
bSleepsForBockCacheDebug =
CPLTestBool(CPLGetConfigOption("GDAL_DEBUG_BLOCK_CACHE", "NO"));

const char *pszCacheMax = CPLGetConfigOption("GDAL_CACHEMAX", "5%");
const char *pszCacheMax = CPLGetConfigOption("GDAL_CACHEMAX", "5%");

GIntBig nNewCacheMax;
if (strchr(pszCacheMax, '%') != nullptr)
{
GIntBig nUsablePhysicalRAM = CPLGetUsablePhysicalRAM();
if (nUsablePhysicalRAM > 0)
GIntBig nNewCacheMax;
if (strchr(pszCacheMax, '%') != nullptr)
{
// For some reason, coverity pretends that this will overflow.
// "Multiply operation overflows on operands
// static_cast<double>( nUsablePhysicalRAM ) and
// CPLAtof(pszCacheMax). Example values for operands: CPLAtof(
// pszCacheMax ) = 2251799813685248,
// static_cast<double>(nUsablePhysicalRAM) =
// -9223372036854775808." coverity[overflow,tainted_data]
double dfCacheMax = static_cast<double>(nUsablePhysicalRAM) *
CPLAtof(pszCacheMax) / 100.0;
if (dfCacheMax >= 0 && dfCacheMax < 1e15)
nNewCacheMax = static_cast<GIntBig>(dfCacheMax);
GIntBig nUsablePhysicalRAM = CPLGetUsablePhysicalRAM();
if (nUsablePhysicalRAM > 0)
{
// For some reason, coverity pretends that this will overflow.
// "Multiply operation overflows on operands
// static_cast<double>( nUsablePhysicalRAM ) and
// CPLAtof(pszCacheMax). Example values for operands: CPLAtof(
// pszCacheMax ) = 2251799813685248,
// static_cast<double>(nUsablePhysicalRAM) =
// -9223372036854775808." coverity[overflow,tainted_data]
double dfCacheMax =
static_cast<double>(nUsablePhysicalRAM) *
CPLAtof(pszCacheMax) / 100.0;
if (dfCacheMax >= 0 && dfCacheMax < 1e15)
nNewCacheMax = static_cast<GIntBig>(dfCacheMax);
else
nNewCacheMax = nCacheMax;
}
else
{
CPLDebug("GDAL", "Cannot determine usable physical RAM.");
nNewCacheMax = nCacheMax;
}
}
else
{
CPLDebug("GDAL", "Cannot determine usable physical RAM.");
nNewCacheMax = nCacheMax;
}
}
else
{
nNewCacheMax = CPLAtoGIntBig(pszCacheMax);
if (nNewCacheMax < 100000)
{
if (nNewCacheMax < 0)
nNewCacheMax = CPLAtoGIntBig(pszCacheMax);
if (nNewCacheMax < 100000)
{
CPLError(CE_Failure, CPLE_NotSupported,
"Invalid value for GDAL_CACHEMAX. "
"Using default value.");
GIntBig nUsablePhysicalRAM = CPLGetUsablePhysicalRAM();
if (nUsablePhysicalRAM)
nNewCacheMax = nUsablePhysicalRAM / 20;
if (nNewCacheMax < 0)
{
CPLError(CE_Failure, CPLE_NotSupported,
"Invalid value for GDAL_CACHEMAX. "
"Using default value.");
GIntBig nUsablePhysicalRAM = CPLGetUsablePhysicalRAM();
if (nUsablePhysicalRAM)
nNewCacheMax = nUsablePhysicalRAM / 20;
else
{
CPLDebug("GDAL",
"Cannot determine usable physical RAM.");
nNewCacheMax = nCacheMax;
}
}
else
{
CPLDebug("GDAL",
"Cannot determine usable physical RAM.");
nNewCacheMax = nCacheMax;
nNewCacheMax *= 1024 * 1024;
}
}
else
{
nNewCacheMax *= 1024 * 1024;
}
}
}
nCacheMax = nNewCacheMax;
CPLDebug("GDAL", "GDAL_CACHEMAX = " CPL_FRMT_GIB " MB",
nCacheMax / (1024 * 1024));
bCacheMaxInitialized = true;
}
nCacheMax = nNewCacheMax;
CPLDebug("GDAL", "GDAL_CACHEMAX = " CPL_FRMT_GIB " MB",
nCacheMax / (1024 * 1024));
});

// coverity[overflow_sink]
return nCacheMax;
}
Expand Down
52 changes: 25 additions & 27 deletions port/cpl_multiproc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,16 +358,16 @@ int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
/************************************************************************/

#ifdef MUTEX_NONE
static int CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
double dfWaitInSeconds,
CPLLockType eType)
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
double dfWaitInSeconds,
CPLLockType eType)
{
return false;
}
#else
static int CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
double dfWaitInSeconds,
CPLLockType eType)
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
double dfWaitInSeconds,
CPLLockType eType)

{
bool bSuccess = false;
Expand Down Expand Up @@ -1462,35 +1462,31 @@ int CPLCreateOrAcquireMutexEx(CPLMutex **phMutex, double dfWaitInSeconds,
int nOptions)

{
bool bSuccess = false;

pthread_mutex_lock(&global_mutex);
if (*phMutex == nullptr)
{
*phMutex = CPLCreateMutexInternal(true, nOptions);
bSuccess = *phMutex != nullptr;
const bool bSuccess = *phMutex != nullptr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the changes in this file related to the TSAN complaint mentioned above?

On a side note, is there chance we can eventually get rid of in-house mutex handling in favor of std:: library methods?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the changes in this file related to the TSAN complaint mentioned above?

not directly, I also incorporated that commit from #1108 because a sanitizer that would test this PR would also frown upon that issue

On a side note, is there chance we can eventually get rid of in-house mutex handling in favor of std:: library methods?

could be a nice cleanup indeed.

pthread_mutex_unlock(&global_mutex);
if (!bSuccess)
return false;
}
else
{
pthread_mutex_unlock(&global_mutex);

bSuccess = CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
}

return bSuccess;
return CPL_TO_BOOL(CPLAcquireMutex(*phMutex, dfWaitInSeconds));
}

/************************************************************************/
/* CPLCreateOrAcquireMutexInternal() */
/************************************************************************/

static int CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
double dfWaitInSeconds,
CPLLockType eType)
static bool CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
double dfWaitInSeconds,
CPLLockType eType)
{
bool bSuccess = false;

pthread_mutex_lock(&global_mutex);
if (*phLock == nullptr)
{
Expand All @@ -1507,18 +1503,17 @@ static int CPLCreateOrAcquireMutexInternal(CPLLock **phLock,
*phLock = nullptr;
}
}
bSuccess = *phLock != nullptr;
const bool bSuccess = *phLock != nullptr;
pthread_mutex_unlock(&global_mutex);
if (!bSuccess)
return false;
}
else
{
pthread_mutex_unlock(&global_mutex);

bSuccess =
CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
}

return bSuccess;
return CPL_TO_BOOL(CPLAcquireMutex((*phLock)->u.hMutex, dfWaitInSeconds));
}

/************************************************************************/
Expand Down Expand Up @@ -1624,20 +1619,23 @@ static CPLMutex *CPLCreateMutexInternal(bool bAlreadyInGlobalLock, int nOptions)
psItem->nOptions = nOptions;
CPLInitMutex(psItem);

// Mutexes are implicitly acquired when created.
CPLAcquireMutex(reinterpret_cast<CPLMutex *>(psItem), 0.0);

return reinterpret_cast<CPLMutex *>(psItem);
}

CPLMutex *CPLCreateMutex()
{
return CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
CPLMutex *mutex = CPLCreateMutexInternal(false, CPL_MUTEX_RECURSIVE);
if (mutex)
CPLAcquireMutex(mutex, 0);
return mutex;
}

CPLMutex *CPLCreateMutexEx(int nOptions)
{
return CPLCreateMutexInternal(false, nOptions);
CPLMutex *mutex = CPLCreateMutexInternal(false, nOptions);
if (mutex)
CPLAcquireMutex(mutex, 0);
return mutex;
}

/************************************************************************/
Expand Down
Loading