Describe the bug
spline() (Thin Plate Spline interpolation) accepts an arbitrary point count N with no upper bound. The TPS solver eagerly builds several O(N²) matrices before any guard runs.
Concrete sites in xrspatial/interpolate/_spline.py:
- Lines 67-70: pairwise difference matrices
dx, dy, r2, and the radial-basis matrix K. Each is N×N float64. About 4 * N² * 8 bytes during construction.
- Line 81: the augmented system matrix
A of shape (N+3, N+3) float64. About (N+3)² * 8 bytes, and np.linalg.solve() typically copies it during LU factorization, doubling the peak.
A user with a moderately large point set hits one of these silently. The process either OOMs or numpy raises a raw MemoryError from inside the linear-algebra call without naming the input that drove the allocation.
Worked example: N=10_000 needs about 800 MB just for K, plus another 800 MB for A. N=40_000 needs about 13 GB for K alone.
Same pattern as the fix in #1309 for the kriging counterpart (issue #1307).
The dask backends still solve the system once on the full point set on the driver, so chunking the template does not help here. The guard has to run before the solve.
Expected behavior
spline() raises MemoryError before allocating, with a message that names the offending allocation (the K block or the augmented A matrix) so the user knows what to reduce.
Reproduce
import numpy as np
import xarray as xr
from xrspatial.interpolate import spline
n = 50_000
x = np.random.rand(n)
y = np.random.rand(n)
z = np.random.rand(n)
template = xr.DataArray(np.zeros((10, 10), dtype=np.float64),
dims=('y', 'x'),
coords={'y': np.arange(10), 'x': np.arange(10)})
# Tries to build a 50_000 x 50_000 K matrix (~20 GB) on the driver.
spline(x, y, z, template)
Severity
MEDIUM. Resource-exhaustion DoS via crafted input. No code execution, but a single call with a large-but-plausible point set takes the process down with no indication of which input was at fault.
Describe the bug
spline()(Thin Plate Spline interpolation) accepts an arbitrary point countNwith no upper bound. The TPS solver eagerly builds several O(N²) matrices before any guard runs.Concrete sites in
xrspatial/interpolate/_spline.py:dx,dy,r2, and the radial-basis matrixK. Each is N×N float64. About4 * N² * 8bytes during construction.Aof shape(N+3, N+3)float64. About(N+3)² * 8bytes, andnp.linalg.solve()typically copies it during LU factorization, doubling the peak.A user with a moderately large point set hits one of these silently. The process either OOMs or numpy raises a raw
MemoryErrorfrom inside the linear-algebra call without naming the input that drove the allocation.Worked example:
N=10_000needs about 800 MB just forK, plus another 800 MB forA.N=40_000needs about 13 GB forKalone.Same pattern as the fix in #1309 for the kriging counterpart (issue #1307).
The dask backends still solve the system once on the full point set on the driver, so chunking the template does not help here. The guard has to run before the solve.
Expected behavior
spline()raisesMemoryErrorbefore allocating, with a message that names the offending allocation (the K block or the augmented A matrix) so the user knows what to reduce.Reproduce
Severity
MEDIUM. Resource-exhaustion DoS via crafted input. No code execution, but a single call with a large-but-plausible point set takes the process down with no indication of which input was at fault.