fix(sgl): guard zero-length lines, NaN fractions, and degenerate segments in linear referencing - #865
Open
connerkup wants to merge 3 commits into
Conversation
…erencing - In linestring::interpolate and linestring::interpolate_points, guard against zero-length linestrings (actual_length == 0) and zero-length segments, eliminating a divide-by-zero that produced NaN/POINT EMPTY and an infinite loop hang in interpolate_points when repeat=true. - In linestring::substring, return early on zero-length linestrings and safely clamp/skip zero-length segments during beg/end point traversal, preventing 0/0 division that corrupted vertices to NaN and produced inverted bounding boxes. - Add comprehensive unit tests in sgl_test.cpp and SQL regression tests in st_lineinterpolatepoint.test.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes three interconnected edge-case bugs in the SGL linear referencing routines (
sgl::linestring::interpolate,sgl::linestring::interpolate_points, andsgl::linestring::substring):ST_LineInterpolatePoints:When invoked with
repeat=trueon a zero-length linestring (e.g.LINESTRING(5 5, 5 5)),actual_lengthevaluates to0.0. In the multi-point accumulation loop,next_targetis incremented byfrac * actual_length = 0.0. The conditionwhile (total_length + segment_length >= next_target)(0.0 >= 0.0) never terminates, causing continuous heap allocation and freezing the worker thread.NaNcoordinate corruption inST_LineSubstring:When a linestring contains degenerate zero-length segments (e.g. leading identical vertices like
LINESTRING(1 1, 1 1, 2 2)atstart_fraction = 0.0or a fully collapsed lineLINESTRING(5 5, 5 5)),segment_lengthis0.0. Evaluatingsfrac = remaining / segment_lengthperforms0.0 / 0.0, injecting IEEE 754NaNcoordinates into the geometry (LINESTRING (nan nan, 1 1, 1.5 1.5)). This also results in inverted bounding box extents (min_x = +1.79e308, max_x = -1.79e308).ST_LineInterpolatePointon collapsed lines:On a zero-length linestring
LINESTRING(5 5, 5 5),linestring::interpolatecomputedsfrac = 0.0 / 0.0 = NaN, returningPOINT EMPTYinstead of returning the coordinatePOINT (5 5).Guarded
beg_fracandend_fracagainstNaNinputs, preventing fall-through that previously emitted a silently corrupted vertex at(0, 0).Changes
src/sgl/sgl.cpp:linestring::interpolate: early return withvertex_arrayifactual_length == 0; skip zero-length segments (segment_length == 0); rejectNaNfractions; fall back to terminal vertex on floating-point precision edge.linestring::interpolate_points: early return withPOINTifactual_length == 0or if(frac * actual_length) <= 0.0(avoiding infinite loops on zero-length and subnormal underflow); skip zero-length segments; rejectNaNfractions.linestring::substring: early return withvertex_arrayiftotal_length == 0; rejectNaNfractions; safely clampbegandendwithout division when encountering degenerate segments wheresegment_length == 0.src/sgl/sgl_test.cpp:-fsanitize=address,undefined).test/sql/geometry/st_lineinterpolatepoint.test:ST_LineSubstring,ST_LineInterpolatePoint, andST_LineInterpolatePointson degenerate lines and duplicate vertices.