Skip to content

Cap erode() parameters and run memory guard on every backend (#1275)#1277

Open
brendancol wants to merge 1 commit intomainfrom
issue-1275
Open

Cap erode() parameters and run memory guard on every backend (#1275)#1277
brendancol wants to merge 1 commit intomainfrom
issue-1275

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Closes #1275.

Summary

  • Caps iterations, params['radius'], and params['max_lifetime'] at the public erode() entry via _validate_scalar(max_val=...). New constants: _MAX_ITERATIONS=1e8, _MAX_RADIUS=1024, _MAX_LIFETIME=1e5. Out-of-range values raise ValueError before any allocation runs.
  • Rewrites _check_erosion_memory to include the random_pos buffer and brush arrays in its budget (the old version only counted the raster). Wires it into _erode_numpy and _erode_cupy so the numpy and cupy paths get the guard too, not just dask.
  • Mirrors the diffuse fix in Guard diffuse() against unbounded allocations and steps loop (#1267) #1268.

Test plan

  • All 15 existing erosion tests still pass
  • New: iterations=0, iterations>cap, iterations=10**12, non-int iterations raise ValueError/TypeError before any allocation
  • New: radius=0, radius>cap raise ValueError
  • New: max_lifetime=0, max_lifetime>cap raise ValueError
  • New: monkeypatched _available_memory_bytes makes the numpy and cupy paths raise MemoryError (dask is no longer the only guarded backend)
  • New: huge iterations on a tiny raster raises MemoryError mentioning random_pos (the buffer dominates)
  • New: defaults still work end-to-end

Deferred follow-ups (per the security-sweep one-fix-per-PR policy)

  • Cat 3 HIGH: NaN input is not guarded in _erode_cpu or _erode_gpu_kernel. A NaN cell propagates through bilinear interpolation into dir_x/dir_y, NaN bounds checks fall through, and particles can deposit NaN via cuda.atomic.add into arbitrary cells of the heightmap.
  • Cat 6 MEDIUM: erode() does not call _validate_raster(). Non-numeric or wrong-ndim input fails inside numba/cupy with a confusing error.

- Cap `iterations`, `params['radius']`, and `params['max_lifetime']` via
  `_validate_scalar(max_val=...)` so `erode()` rejects pathological values
  before any allocation runs.
- Rewrite `_check_erosion_memory` to include the `random_pos` buffer and
  brush working set in its budget, and wire it into `_erode_numpy` and
  `_erode_cupy` so every backend hits the guard. The dask paths inherit
  the check through their inner numpy/cupy calls.
- Add 13 tests covering each cap, the memory guard on numpy and cupy,
  and the random_pos-dominated case.

Mirrors the diffuse fix in #1268. Cat 3 NaN propagation and Cat 6 missing
`_validate_raster` are deferred to separate PRs and tracked in the issue.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cap iterations / radius / max_lifetime in erode() and run memory guard on every backend

1 participant