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

GDALDefaultOverviews::OverviewScan(): avoid very long processing time… #2207

Merged
merged 1 commit into from Feb 1, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
62 changes: 54 additions & 8 deletions gdal/gcore/gdaldefaultoverviews.cpp
Expand Up @@ -29,12 +29,14 @@
****************************************************************************/

#include "cpl_port.h"
#include "cpl_multiproc.h"
#include "gdal_priv.h"

#include <cstdlib>
#include <cstring>

#include <algorithm>
#include <set>
#include <string>
#include <vector>

Expand Down Expand Up @@ -180,6 +182,46 @@ void GDALDefaultOverviews::TransferSiblingFiles( char** papszSiblingFiles )
papszInitSiblingFiles = papszSiblingFiles;
}


namespace {
// Prevent infinite recursion.
struct AntiRecursionStruct
{
int nRecLevel = 0;
std::set<CPLString> oSetFiles{};
};
}

static void FreeAntiRecursion( void* pData )
{
delete static_cast<AntiRecursionStruct*>(pData);
}

static AntiRecursionStruct& GetAntiRecursion()
{
static AntiRecursionStruct dummy;
int bMemoryErrorOccurred = false;
void* pData = CPLGetTLSEx(CTLS_GDALDEFAULTOVR_ANTIREC, &bMemoryErrorOccurred);
if( bMemoryErrorOccurred )
{
return dummy;
}
if( pData == nullptr)
{
auto pAntiRecursion = new AntiRecursionStruct();
CPLSetTLSWithFreeFuncEx( CTLS_GDALDEFAULTOVR_ANTIREC,
pAntiRecursion,
FreeAntiRecursion, &bMemoryErrorOccurred );
if( bMemoryErrorOccurred )
{
delete pAntiRecursion;
return dummy;
}
return *pAntiRecursion;
}
return *static_cast<AntiRecursionStruct*>(pData);
}

/************************************************************************/
/* OverviewScan() */
/* */
Expand All @@ -196,21 +238,23 @@ void GDALDefaultOverviews::OverviewScan()
return;

bCheckedForOverviews = true;
if( pszInitName == nullptr )
pszInitName = CPLStrdup(poDS->GetDescription());

static thread_local int nAntiRecursionCounter = 0;
// arbitrary number. 32 should be enough to handle a .ovr.ovr.ovr...
if( nAntiRecursionCounter == 64 )
AntiRecursionStruct& antiRec = GetAntiRecursion();
// 32 should be enough to handle a .ovr.ovr.ovr...
if( antiRec.nRecLevel == 32 )
return;
if( antiRec.oSetFiles.find(pszInitName) != antiRec.oSetFiles.end() )
return;
++nAntiRecursionCounter;
antiRec.oSetFiles.insert(pszInitName);
++antiRec.nRecLevel;

CPLDebug( "GDAL", "GDALDefaultOverviews::OverviewScan()" );

/* -------------------------------------------------------------------- */
/* Open overview dataset if it exists. */
/* -------------------------------------------------------------------- */
if( pszInitName == nullptr )
pszInitName = CPLStrdup(poDS->GetDescription());

if( !EQUAL(pszInitName,":::VIRTUAL:::") &&
GDALCanFileAcceptSidecarFile(pszInitName) )
{
Expand Down Expand Up @@ -359,7 +403,9 @@ void GDALDefaultOverviews::OverviewScan()
}
}

--nAntiRecursionCounter;
// Undo anti recursion protection
antiRec.oSetFiles.erase(pszInitName);
--antiRec.nRecLevel;
}

/************************************************************************/
Expand Down
1 change: 1 addition & 0 deletions gdal/port/cpl_multiproc.h
Expand Up @@ -227,6 +227,7 @@ class CPL_DLL CPLLockHolder
#define CTLS_VSIERRORCONTEXT 16 /* cpl_vsi_error.cpp */
#define CTLS_ERRORHANDLERACTIVEDATA 17 /* cpl_error.cpp */
#define CTLS_PROJCONTEXTHOLDER 18 /* ogr_proj_p.cpp */
#define CTLS_GDALDEFAULTOVR_ANTIREC 19 /* gdaldefaultoverviews.cpp */

#define CTLS_MAX 32

Expand Down