Skip to content

interior_point() panics on a polygon that check_validation() accepts, when coordinates contain -0.0 #1578

Description

@PlenoraETL

geo 0.33.1. A polygon containing a negative zero coordinate is reported as valid by check_validation(), but interior_point() then trips its own internal debug_assert! in the sweep line.

Minimal reproducer — only geo = "=0.33.1", with debug-assertions = true:

use geo::algorithm::{InteriorPoint, Validation};
use geo::{Coord, LineString, Polygon};

fn main() {
let ring = LineString(vec![
Coord { x: 5.0, y: 22.0 },
Coord { x: 2.0, y: 7.0 },
Coord { x: -0.0, y: 423.0 }, // negative zero
Coord { x: 0.0, y: 3.0 },
Coord { x: 9.0, y: 0.0 },
Coord { x: 5.0, y: 22.0 },
]);
let poly = Polygon::new(ring, vec![]);

assert!(poly.check_validation().is_ok()); // passes
let _ = poly.interior_point();            // panics

}

assertion failed: intervals_overlap(current_interval, overlapping_interval)
geo-0.33.1/src/algorithm/sweep/mod.rs:169

Replacing -0.0 with 0.0, leaving every other coordinate untouched, makes it return POINT(0.5084134615384616 211.5). The two polygons are numerically identical, since -0.0 == 0.0.

Root cause. src/algorithm/sweep/mod.rs mixes two incompatible orderings:

  • line 266 sorts with total_cmp, and intervals_overlap (lines 277-280) compares with total_cmp — a total order, where -0.0 < +0.0;
  • line 163 guards with the IEEE operator: if overlapping_interval.inserted_x > current_interval.deleted_x.

With deleted_x == -0.0 and inserted_x == 0.0 the IEEE guard is false, so the pair is not skipped, while intervals_overlap returns false because (-0.0).total_cmp(&0.0) is Less. The assertion then fails. Signed zero is precisely where the two orderings disagree on equal values.

Suggested fix. Make line 163 use the same ordering as the rest of the module:

if overlapping_interval.inserted_x.total_cmp(&current_interval.deleted_x).is_gt() {

Why it matters beyond the panic. It is a debug_assert!, so in release builds the check is compiled out and the sweep proceeds with a violated invariant — interior_point() can then return a wrong point silently. We only noticed because cargo-fuzz enables debug assertions.

Found by fuzzing a WKT parsing and geometry operations pipeline; the input was POLYGON((5 22, 2 7, -0 423, 0 3, 9 0, 5 22)).

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