Skip to content

spline TPS: unbounded N\xc3\x97N system has no memory guard #1372

@brendancol

Description

@brendancol

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinginput-validationInput validation and error messagesoomOut-of-memory risk with large datasets

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions