From 05d2c96c1da85b20edc88c0827287e3e00021877 Mon Sep 17 00:00:00 2001 From: gsdali <51393997+gsdali@users.noreply.github.com> Date: Sun, 19 Jul 2026 22:54:43 +1000 Subject: [PATCH 1/3] Modeling Algorithms - use the adaptor's NbPoles() in BRepGProp_EdgeTool::IntegrationOrder BRepGProp::LinearProperties crashes (uncatchable SIGSEGV) computing the integration order for a Bezier- or BSpline-type edge that has no 3D curve, only a curve-on-surface (pcurve) representation with that curve type -- the common case for a degenerate edge produced by BRepBuilderAPI_Sewing when it merges near-coincident vertices between two faces that don't share an edge outright. Root cause: IntegrationOrder branches on BAC.GetType() (a BRepAdaptor_Curve), which correctly reports the curve-on-surface pcurve's type via GeomAdaptor_TransformedCurve::GetType()'s override, but then reads the pole count via a completely different, non-virtual path: BAC.Curve().Curve(), down-cast to Geom_BezierCurve/Geom_BSplineCurve. BAC.Curve() returns the base GeomAdaptor_Curve sub-object, which holds the 3D-curve representation only -- it is never Load()ed when the edge has no 3D curve, so the handle is null, the down_cast returns null, and ->NbPoles() dereferences it. GeomAdaptor_TransformedCurve already has a correctly-dispatching NbPoles() override next to GetType() in the same header. Calling BAC.NbPoles() instead fixes the crash and matches the accessor GetType() one line above it already uses -- no cast, no null check needed, and no behaviour change for an edge that does have a 3D curve. Reported downstream and isolated at SecondMouseAU/OCCTSwift#318. --- .../TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx b/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx index b75902b1950..c20d1f7ff93 100644 --- a/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx +++ b/src/ModelingAlgorithms/TKTopAlgo/BRepGProp/BRepGProp_EdgeTool.cxx @@ -42,19 +42,11 @@ int BRepGProp_EdgeTool::IntegrationOrder(const BRepAdaptor_Curve& BAC) case GeomAbs_Parabola: return 5; - case GeomAbs_BezierCurve: { - const GeomAdaptor_Curve& GAC = BAC.Curve(); - const occ::handle& GC = GAC.Curve(); - occ::handle GBZC(occ::down_cast(GC)); - int n = 2 * (GBZC->NbPoles()) - 1; - return n; - } - break; + case GeomAbs_BezierCurve: case GeomAbs_BSplineCurve: { - const GeomAdaptor_Curve& GAC = BAC.Curve(); - const occ::handle& GC = GAC.Curve(); - occ::handle GBSC(occ::down_cast(GC)); - int n = 2 * (GBSC->NbPoles()) - 1; + // Use the adaptor's own NbPoles(), which handles the curve-on-surface case; + // Curve() is null there and down-casting it segfaults. + int n = 2 * BAC.NbPoles() - 1; return n; } break; From 95ca02a3b83f4454a96d0787fabcde555a64ece6 Mon Sep 17 00:00:00 2001 From: gsdali <51393997+gsdali@users.noreply.github.com> Date: Sun, 19 Jul 2026 22:54:49 +1000 Subject: [PATCH 2/3] Tests - Add GTest for BRepGProp_EdgeTool::IntegrationOrder degenerate curve-on-surface crash (#318) Regression test for the fix in the previous commit: a degenerate edge whose sole geometric representation is a Bezier/BSpline-type curve-on-surface pcurve (no 3D curve) used to SIGSEGV inside IntegrationOrder. Verifies LinearProperties completes and returns a finite, non-negative length. --- .../TKTopAlgo/GTests/BRepGProp_Test.cxx | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx index bbe175b7d96..8c238bf79a7 100644 --- a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx @@ -17,16 +17,24 @@ #include #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include #include #include +#include +#include +#include #include +#include #include #include #include @@ -34,6 +42,8 @@ #include +#include + TEST(BRepGPropTest, LinearProperties_EdgeLength) { gp_Pnt aP1(0.0, 0.0, 0.0); @@ -195,3 +205,49 @@ TEST(BRepGPropTest, OCC8797_BSplineLengthConsistencyAbscissaVsLinearProperties) // Both methods must agree within 0.1 % EXPECT_NEAR(aLengthAbscissa, aLengthGProp, aLengthGProp * 1e-3); } + +// Regression: a degenerate edge whose ONLY representation is a Bezier/BSpline-type +// curve-on-surface pcurve (no 3D curve) used to SIGSEGV inside +// BRepGProp_EdgeTool::IntegrationOrder, which read the pole count via BAC.Curve().Curve() +// (null when there is no 3D curve) instead of the adaptor's own NbPoles(). This is the +// shape BRepBuilderAPI_Sewing produces reconciling near-coincident vertices between two +// faces that do not share an edge outright. +TEST(BRepGPropTest, LinearProperties_DegenerateEdgeWithBSplinePCurveNoCrash) +{ + occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); + + TColgp_Array1OfPnt2d aPoles(1, 4); + aPoles.SetValue(1, gp_Pnt2d(0.0, 0.0)); + aPoles.SetValue(2, gp_Pnt2d(0.1, 0.05)); + aPoles.SetValue(3, gp_Pnt2d(0.2, -0.05)); + aPoles.SetValue(4, gp_Pnt2d(0.3, 0.0)); + + TColStd_Array1OfReal aKnots(1, 2); + aKnots.SetValue(1, 0.0); + aKnots.SetValue(2, 1.0); + + TColStd_Array1OfInteger aMults(1, 2); + aMults.SetValue(1, 4); + aMults.SetValue(2, 4); + + occ::handle aPCurve = new Geom2d_BSplineCurve(aPoles, aKnots, aMults, 3); + + BRep_Builder aBuilder; + TopoDS_Edge anEdge; + aBuilder.MakeEdge(anEdge); + aBuilder.UpdateEdge(anEdge, aPCurve, aPlane, TopLoc_Location(), Precision::Confusion()); + aBuilder.Range(anEdge, + aPlane, + TopLoc_Location(), + aPCurve->FirstParameter(), + aPCurve->LastParameter()); + aBuilder.Degenerated(anEdge, true); + + GProp_GProps aProps; + BRepGProp::LinearProperties(anEdge, aProps); + + // Reaching this point at all is the regression check: IntegrationOrder used to SIGSEGV + // before returning. + EXPECT_TRUE(std::isfinite(aProps.Mass())); + EXPECT_GE(aProps.Mass(), 0.0); +} From 355c7623817058ade0d408558f485220a2ab96cc Mon Sep 17 00:00:00 2001 From: gsdali <51393997+gsdali@users.noreply.github.com> Date: Mon, 20 Jul 2026 12:07:57 +1000 Subject: [PATCH 3/3] Tests - Use NCollection_Array1 directly instead of deprecated TColgp/TColStd aliases TColgp_Array1OfPnt2d.hxx, TColStd_Array1OfInteger.hxx and TColStd_Array1OfReal.hxx moved to src/Deprecated/NCollectionAliases in OCCT 8.0.0; that toolkit isn't on TKTopAlgo's GTest include path, so CI failed with a missing-header error on all platforms. Geom2d_BSplineCurve already takes NCollection_Array1 natively. --- .../TKTopAlgo/GTests/BRepGProp_Test.cxx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx index 8c238bf79a7..189b286dd98 100644 --- a/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx +++ b/src/ModelingAlgorithms/TKTopAlgo/GTests/BRepGProp_Test.cxx @@ -30,9 +30,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -216,17 +213,17 @@ TEST(BRepGPropTest, LinearProperties_DegenerateEdgeWithBSplinePCurveNoCrash) { occ::handle aPlane = new Geom_Plane(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0)); - TColgp_Array1OfPnt2d aPoles(1, 4); + NCollection_Array1 aPoles(1, 4); aPoles.SetValue(1, gp_Pnt2d(0.0, 0.0)); aPoles.SetValue(2, gp_Pnt2d(0.1, 0.05)); aPoles.SetValue(3, gp_Pnt2d(0.2, -0.05)); aPoles.SetValue(4, gp_Pnt2d(0.3, 0.0)); - TColStd_Array1OfReal aKnots(1, 2); + NCollection_Array1 aKnots(1, 2); aKnots.SetValue(1, 0.0); aKnots.SetValue(2, 1.0); - TColStd_Array1OfInteger aMults(1, 2); + NCollection_Array1 aMults(1, 2); aMults.SetValue(1, 4); aMults.SetValue(2, 4);