Fix crash/hang in DRC zone-zone clearance check

SEG::operator< delegates to VECTOR2I::operator< which compares by
squared magnitude. When SEG::operator< mixes this magnitude comparison
with VECTOR2I::operator== (exact coordinate equality) for tie-breaking,
it violates strict weak ordering: two points at the same magnitude but
different coordinates are "incomparable" under operator< but "unequal"
under operator==, breaking transitivity of incomparability.

Replace the default SEG::operator< sort with a lexicographic comparator
on x/y coordinates, which provides a proper strict weak ordering and
matches the sweep-line optimization that follows (breaking the inner
loop when refSegment.B.x < testSegment.A.x).

Also add null checks for polyA/polyB from GetFill() before dereferencing.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/23112
This commit is contained in:
Seth Hillbrand
2026-02-16 14:02:44 -08:00
parent 9dbffdffeb
commit 3f69a07e89
@@ -1376,7 +1376,24 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
zone_layer_poly_segs.push_back( seg );
}
std::sort( zone_layer_poly_segs.begin(), zone_layer_poly_segs.end() );
// Sort by x-coordinates for the sweep-line optimization in the inner
// loop. SEG::operator< must not be used here because it delegates to
// VECTOR2I::operator< which compares by magnitude, violating strict
// weak ordering when mixed with VECTOR2I::operator== for tie-breaking.
std::sort( zone_layer_poly_segs.begin(), zone_layer_poly_segs.end(),
[]( const SEG& a, const SEG& b ) -> bool
{
if( a.A.x != b.A.x )
return a.A.x < b.A.x;
if( a.A.y != b.A.y )
return a.A.y < b.A.y;
if( a.B.x != b.B.x )
return a.B.x < b.B.x;
return a.B.y < b.B.y;
} );
}
}
}
@@ -1420,7 +1437,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
polyB = zoneB->GetFill( layer );
}
if( !polyA->BBoxFromCaches().Intersects( polyB->BBoxFromCaches() ) )
if( !polyA || !polyB
|| !polyA->BBoxFromCaches().Intersects( polyB->BBoxFromCaches() ) )
continue;
count++;