Guard float overlay entry points against non-finite coordinates#82
Guard float overlay entry points against non-finite coordinates#82LucaCappelletti94 wants to merge 1 commit into
Conversation
|
Thanks for the detailed fuzz report and for covering the failure modes with tests. I agree that non-finite coordinates should not be able to reach iOverlay is designed around valid geometric input. I would prefer to handle this as an explicit input precondition:
To make this clean across custom point types, I propose first adding an pub trait FloatNumber {
fn is_finite(self) -> bool;
}
pub trait FloatPointCompatible: Copy {
type Scalar: FloatNumber;
fn from_xy(x: Self::Scalar, y: Self::Scalar) -> Self;
fn x(&self) -> Self::Scalar;
fn y(&self) -> Self::Scalar;
#[inline(always)]
fn is_finite(&self) -> bool {
self.x().is_finite() && self.y().is_finite()
}
} |
|
For what it's worth, that seems reasonable to me. |
|
The panic came from fuzzing an app that reaches The I would rather make the checked constructors ( |
|
Could you please stop AI pumping your comments? I think it will be more productive to talk in your own voice rather than dumping paragraphs of inflated text. |
That is just me being precise. If you prefer an even shorter TLDR: methods that fail should return |
|
Sorry I do not want iOverlay to silently modify invalid geometry. But if you d' like to add some |
|
Nothing forces What I am working on is SqliteGIS, a pure-Rust reimplementation of PostGIS on top of SQLite and geo. It accepts arbitrary SQL where
|
|
ok I do not want to change the existing fast constructors. For the main use case this is redundant overhead. But I don't mind to add additional api with safe guarantees Lets first add this api to iFloat and iShape FloatNumber::is_finite()
FloatPointCompatible::is_finite() with the default impl for traitand for iShape probably better place will be here: enum InvalidGeometry {
NonFinitePoint {
path_index: usize,
point_index: usize,
},
}
pub trait ShapeResource<P>
where
P: FloatPointCompatible,
{
type ResourceIter<'a>: Iterator<Item = &'a [P]>
where
P: 'a,
Self: 'a;
fn iter_paths(&self) -> Self::ResourceIter<'_>;
fn validate_finite_points(&self) -> Result<(), InvalidGeometry> {
for (path_index, path) in self.iter_paths().enumerate() {
for (point_index, p) in path.iter().enumerate() {
if !p.is_finite() {
return Err(InvalidGeometry::NonFinitePoint {
path_index,
point_index,
});
}
}
}
Ok(())
}
}Do we need the detailed information about contour index? and after we can duplicate some api with this exception for iOverlay |
Float boolean ops and mesh offsetters aborted on NaN or infinite input: the adapter's
FloatRectinherited NaN bounds, andi_float'sFloatPointAdapter::float_to_intdebug assertion then fired on the first point converted. A downstreamgeofuzz report againsti_overlay4.5.2 andi_float1.16.0 hit this out ofBooleanOpsandBuffer.Every public entry point that builds an adapter from user paths now filters non-finite points before
FloatPointAdapter::with_iter(or the meshFloatRect::with_iter), and every per-contour loop skips contours containing any non-finite point before touchingfloat_to_intorunsafe_int_area. Both guards are needed: the first keeps the rect finite, the second keeps NaN out of the integer conversion.unsafe_add_contourstays ungated on purpose, its safety contract already excludes points outside the rect.Eleven regression tests in
tests/float_point_adapter.rscover NaN,f64::INFINITY,f64::NEG_INFINITY,f32NaN, mixed and degenerate contours,from_subj_and_clipcombinations, and an empty contour. They pass under both debug (with thei_floatadapter assertions active) and release alongside the 667 existing tests.Also folds in a few unrelated clippy cleanups.