Skip to content

Panic "index out of bounds" in i_overlay bind/solver.rs during ST_Buffer on a valid polygon with a degenerate interior ring #1178

Description

@lukeplatts

Describe the bug

ST_Buffer panics inside i_overlay's hole-binding solver when the input is a
valid polygon containing a degenerate (near-zero-area) interior ring, once the
buffer distance is large enough to consume that hole.

pyo3_runtime.PanicException: index out of bounds: the len is 1 but the index is 9223372036854775807

from

thread '<unnamed>' panicked at .../i_overlay-4.0.7/src/bind/solver.rs:91:33

9223372036854775807 is i64::MAX, which suggests an uninitialised sentinel index
escaping rather than an ordinary off-by-one.

We ran into this issue performing some data processing on a real-world dataset of building footprints.

The hole is required. Buffering the same exterior ring with the interior ring
dropped succeeds at every distance tried. That is consistent with the panic site being
bind/solver.rs, the code binding holes to their parent contour.

GEOS buffers the identical geometry without complaint (shapely 2.1.2 / GEOS 3.14.1),
so this looks specific to i_overlay rather than a general geometry-engine limit.

Because it surfaces as a PanicException — which subclasses BaseException, not
Exception — it cannot be caught by ordinary Python error handling, so one bad row
takes down the whole process.

To Reproduce

import sedonadb

# Valid polygon: a thin triangle containing one degenerate sliver hole.
# ST_Area 330.0808, hole area ~0.096. Coordinates are in an arbitrary local frame,
# rounded to 4 decimal places.
WKT = (
    "POLYGON ("
    "(0 0, 208.1046 9.4235, 208.2609 6.2574, 0 0), "
    "(103.4778 4.061, 103.476 4.0517, 103.4742 4.0415, 103.4706 4.0314, "
    "103.4626 3.994, 103.4626 3.9847, 103.4608 3.9746, 103.459 3.9465, "
    "104.5244 3.501, 104.5307 3.5096, 104.5477 3.522, 104.5558 3.5291, "
    "104.5639 3.5376, 103.4778 4.061))"
)

sd = sedonadb.connect()

# The input is valid.
print("ST_IsValid:", sd.sql(
    f"SELECT ST_IsValid(ST_GeomFromWKT('{WKT}'))"
).to_arrow_table().column(0)[0].as_py())

# Panics here.
sd.sql(f"SELECT ST_Buffer(ST_GeomFromWKT('{WKT}'), 10.0)").to_arrow_table()
print("no panic")

Output:

ST_IsValid: True
thread '<unnamed>' panicked at .../i_overlay-4.0.7/src/bind/solver.rs:91:33:
index out of bounds: the len is 1 but the index is 9223372036854775807

Buffer distance dependence

distance with the hole hole dropped
0.001 OK (55 pts) OK (36 pts)
0.01 OK (52 pts) OK (36 pts)
0.1 OK (36 pts) OK (36 pts)
1 OK (40 pts) OK (36 pts)
5 OK (44 pts) OK (36 pts)
5.8 OK (56 pts) OK (36 pts)
6 … 70 panic OK (36 pts)
75 OK (56 pts) OK (36 pts)
100 OK (44 pts) OK (36 pts)

The panic window is 6 <= distance <= 70, i.e. once the buffer is large enough to
consume the degenerate hole but before it is large enough to swallow the whole
20-unit-wide feature. The same exterior ring with the interior ring dropped never
panics at any distance.

Expected behavior

ST_Buffer returns a buffered geometry, or raises a catchable error — rather than
panicking.

What I checked

  • Not invalid input — ST_IsValid is True.
  • Not ST_MakeValid — the panic is strictly inside ST_Buffer. ST_MakeValid also
    does not remove the degenerate hole, so it is not a workaround.
  • Not a coordinate-system or transform issue — no transform is involved, and the panic
    is unaffected by translation or uniform scaling.
  • Not the buffer style — the 2-arg round form above is enough.
  • Note that bind/solver.rs is unchanged between i_overlay 4.0.6 and 4.0.7, and the
    0.4.1-rc0 tag locks the same 4.0.7.

Environment

  • sedonadb: 0.4.0 (PyPI), the latest published release
  • i_overlay: 4.0.7
  • Python: 3.12
  • OS: osx-arm64

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions