Skip to content

Commit a7ad676

Browse files
authored
Merge pull request #14376 from dbaston/gdal-raster-zonal-stats-invalid-write
gdal raster zonal-stats: fix alloc of buffers for cell center coords
2 parents 19ba87a + f52ec7f commit a7ad676

2 files changed

Lines changed: 91 additions & 29 deletions

File tree

alg/zonal.cpp

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,9 @@ class GDALZonalStatsImpl
993993
return ret;
994994
}
995995

996+
bool ReallocCellCenterBuffersIfNeeded(size_t &nBufXSize, size_t &nBufYSize,
997+
const GDALRasterWindow &oWindow);
998+
996999
void WarnIfZonesNotCovered(const GDALRasterBand *poZonesBand) const
9971000
{
9981001
OGREnvelope oZonesEnv;
@@ -1117,6 +1120,8 @@ class GDALZonalStatsImpl
11171120

11181121
auto pabyZonesBuf = CreateBuffer();
11191122
size_t nBufSize = 0;
1123+
size_t nBufXSize = 0;
1124+
size_t nBufYSize = 0;
11201125

11211126
const auto windowIteratorWrapper =
11221127
poAlignedValuesDS->GetRasterBand(1)->IterateWindows(m_maxCells);
@@ -1126,6 +1131,11 @@ class GDALZonalStatsImpl
11261131
{
11271132
const auto nWindowSize = static_cast<size_t>(oWindow.nXSize) *
11281133
static_cast<size_t>(oWindow.nYSize);
1134+
if (!ReallocCellCenterBuffersIfNeeded(nBufXSize, nBufYSize,
1135+
oWindow))
1136+
{
1137+
return false;
1138+
}
11291139

11301140
if (nBufSize < nWindowSize)
11311141
{
@@ -1140,16 +1150,6 @@ class GDALZonalStatsImpl
11401150
GDALGetDataTypeSizeBytes(m_maskDataType),
11411151
bAllocSuccess);
11421152

1143-
if (m_stats_options.store_xy)
1144-
{
1145-
Realloc(m_padfX, oWindow.nXSize,
1146-
GDALGetDataTypeSizeBytes(GDT_Float64),
1147-
bAllocSuccess);
1148-
Realloc(m_padfY, oWindow.nYSize,
1149-
GDALGetDataTypeSizeBytes(GDT_Float64),
1150-
bAllocSuccess);
1151-
}
1152-
11531153
if (poWeightsBand)
11541154
{
11551155
Realloc(m_padfWeightsBuf, nWindowSize,
@@ -1370,6 +1370,8 @@ class GDALZonalStatsImpl
13701370
auto addHit = [](void *hit, void *hits)
13711371
{ static_cast<std::vector<void *> *>(hits)->push_back(hit); };
13721372
size_t nBufSize = 0;
1373+
size_t nBufXSize = 0;
1374+
size_t nBufYSize = 0;
13731375

13741376
const auto windowIteratorWrapper =
13751377
m_src.GetRasterBand(m_options.bands.front())
@@ -1399,6 +1401,12 @@ class GDALZonalStatsImpl
13991401

14001402
if (!aiHits.empty())
14011403
{
1404+
if (!ReallocCellCenterBuffersIfNeeded(nBufXSize, nBufYSize,
1405+
oChunkWindow))
1406+
{
1407+
return false;
1408+
}
1409+
14021410
if (nBufSize < nWindowSize)
14031411
{
14041412
bool bAllocSuccess = true;
@@ -1411,15 +1419,6 @@ class GDALZonalStatsImpl
14111419
Realloc(m_pabyMaskBuf, nWindowSize,
14121420
GDALGetDataTypeSizeBytes(m_maskDataType),
14131421
bAllocSuccess);
1414-
if (m_stats_options.store_xy)
1415-
{
1416-
Realloc(m_padfX, oChunkWindow.nXSize,
1417-
GDALGetDataTypeSizeBytes(GDT_Float64),
1418-
bAllocSuccess);
1419-
Realloc(m_padfY, oChunkWindow.nYSize,
1420-
GDALGetDataTypeSizeBytes(GDT_Float64),
1421-
bAllocSuccess);
1422-
}
14231422
if (m_weights != nullptr)
14241423
{
14251424
Realloc(m_padfWeightsBuf, nWindowSize,
@@ -1619,6 +1618,8 @@ class GDALZonalStatsImpl
16191618
}
16201619

16211620
size_t nBufSize = 0;
1621+
size_t nBufXSize = 0;
1622+
size_t nBufYSize = 0;
16221623

16231624
OGRLayer *poSrcLayer = std::get<OGRLayer *>(m_zones);
16241625
OGRLayer *poDstLayer = GetOutputLayer(false);
@@ -1699,6 +1700,12 @@ class GDALZonalStatsImpl
16991700
const size_t nWindowSize = static_cast<size_t>(oWindow.nXSize) *
17001701
static_cast<size_t>(nRowsPerChunk);
17011702

1703+
if (!ReallocCellCenterBuffersIfNeeded(nBufXSize, nBufYSize,
1704+
oWindow))
1705+
{
1706+
return false;
1707+
}
1708+
17021709
if (nBufSize < nWindowSize)
17031710
{
17041711
bool bAllocSuccess = true;
@@ -1712,16 +1719,6 @@ class GDALZonalStatsImpl
17121719
GDALGetDataTypeSizeBytes(m_maskDataType),
17131720
bAllocSuccess);
17141721

1715-
if (m_stats_options.store_xy)
1716-
{
1717-
Realloc(m_padfX, oWindow.nXSize,
1718-
GDALGetDataTypeSizeBytes(GDT_Float64),
1719-
bAllocSuccess);
1720-
Realloc(m_padfY, oWindow.nYSize,
1721-
GDALGetDataTypeSizeBytes(GDT_Float64),
1722-
bAllocSuccess);
1723-
}
1724-
17251722
if (m_weights != nullptr)
17261723
{
17271724
Realloc(m_padfWeightsBuf, nWindowSize,
@@ -1995,6 +1992,43 @@ class GDALZonalStatsImpl
19951992
#endif
19961993
};
19971994

1995+
bool GDALZonalStatsImpl::ReallocCellCenterBuffersIfNeeded(
1996+
size_t &nBufXSize, size_t &nBufYSize, const GDALRasterWindow &oWindow)
1997+
{
1998+
if (!m_stats_options.store_xy)
1999+
{
2000+
return true;
2001+
}
2002+
2003+
if (nBufXSize < static_cast<size_t>(oWindow.nXSize))
2004+
{
2005+
bool bAllocSuccess = true;
2006+
Realloc(m_padfX, oWindow.nXSize, GDALGetDataTypeSizeBytes(GDT_Float64),
2007+
bAllocSuccess);
2008+
if (!bAllocSuccess)
2009+
{
2010+
return false;
2011+
}
2012+
2013+
nBufXSize = static_cast<size_t>(oWindow.nXSize);
2014+
}
2015+
2016+
if (nBufYSize < static_cast<size_t>(oWindow.nYSize))
2017+
{
2018+
bool bAllocSuccess = true;
2019+
Realloc(m_padfY, oWindow.nYSize, GDALGetDataTypeSizeBytes(GDT_Float64),
2020+
bAllocSuccess);
2021+
if (!bAllocSuccess)
2022+
{
2023+
return false;
2024+
}
2025+
2026+
nBufYSize = static_cast<size_t>(oWindow.nYSize);
2027+
}
2028+
2029+
return true;
2030+
}
2031+
19982032
static CPLErr GDALZonalStats(GDALDataset &srcDataset, GDALDataset *poWeights,
19992033
GDALDataset &zonesDataset, GDALDataset &dstDataset,
20002034
const GDALZonalStatsOptions &options,

autotest/utilities/test_gdalalg_raster_zonal_stats.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,3 +1247,31 @@ def test_gdalalg_raster_zonal_stats_raster_zones_output_layer(zonal):
12471247
out_ds = zonal.Output()
12481248

12491249
assert out_ds.GetLayer(0).GetName() == "myresult"
1250+
1251+
1252+
@pytest.mark.parametrize("pixels", ["default", "all-touched"], indirect=True)
1253+
def test_gdalalg_raster_zonal_stats_center_xy_alloc(zonal, strategy, pixels):
1254+
1255+
# See https://github.com/OSGeo/gdal/issues/14371#issuecomment-4256674808
1256+
1257+
nx, ny = 10, 10
1258+
1259+
src_ds = gdal.GetDriverByName("MEM").Create("", nx, ny, 1)
1260+
src_ds.SetGeoTransform((0, 1, 0, ny, 0, -1))
1261+
1262+
zones_ds = gdaltest.wkt_ds(
1263+
[
1264+
"POLYGON ((0 0, 1 0, 1 10, 0 10, 0 1))",
1265+
"POLYGON ((0 0, 10 0, 10 1, 0 1, 0 0))",
1266+
]
1267+
)
1268+
1269+
zonal["input"] = src_ds
1270+
zonal["zones"] = zones_ds
1271+
zonal["output"] = ""
1272+
zonal["output-format"] = "MEM"
1273+
zonal["strategy"] = strategy
1274+
zonal["pixels"] = pixels
1275+
zonal["stat"] = ["count", "center_x", "center_y"]
1276+
1277+
assert zonal.Run() # no crash

0 commit comments

Comments
 (0)