Skip to content

fix(#263): carry OCCT kernel patch — ShapeFix_Face non-face context replacement#265

Merged
gsdali merged 3 commits into
mainfrom
fix/263-occt-shapefix-kernel-patch
Jun 26, 2026
Merged

fix(#263): carry OCCT kernel patch — ShapeFix_Face non-face context replacement#265
gsdali merged 3 commits into
mainfrom
fix/263-occt-shapefix-kernel-patch

Conversation

@gsdali

@gsdali gsdali commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Draft — carries the upstream OCCT kernel fix for #263. Takes effect only on the next xcframework rebuild; the in-wrapper guard shipped in v1.8.3 (#264) protects consumers until then.

Root cause (upstream OCCT — Open-Cascade-SAS/OCCT#1322)

ShapeFix_Face::Perform (ShapeFix_Face.cxx:382-383) does:

TopoDS_Shape S = myFace;
if (!Context().IsNull()) S = Context()->Apply(myFace);
TopoDS_Shape emptyCopied = S.EmptyCopied();
TopoDS_Face  tmpFace     = TopoDS::Face(emptyCopied);   // <-- unchecked cast

When an earlier fix sharing the same ShapeBuild_ReShape context has replaced the face with a compound (a self-intersecting face split into several faces), Apply() returns a non-face. TopoDS::Face over a compound TShape builds an invalid face handle → heap corruption → uncatchable OS signal downstream (FixOrientationBRep_Tool::CurveBRep_TEdge::EmptyCopy, SIGSEGV/SIGBUS at varying addresses — the exact #263 backtrace).

Pinned by linking a debug-built ShapeFix_Face.cxx over the prebuilt lib: at -O0 the cast throws Standard_TypeMismatch at line 383 with S.type=COMPOUND, myFace.type=FACE (on the 6th of 6 prism faces; the first 5 fix cleanly).

Fix

Guard the cast — if S is not a TopAbs_FACE, record it as the result and return (the replacement is already in the context; nothing to fix here). One carried patch: Scripts/patches/0001-ShapeFix_Face-guard-non-face-context-replacement-263.patch.

Validation (single-TU override-link at -O2, no full rebuild)

  • Bowtie reproducer: crashes 3/3 on stock OCCT 8.0.0p1 → survives 5/5 patched.
  • All four OCCTReconstruct crash-repro fixtures (b1214/b693/b135/b106): survive.
  • ShapeFix_Shape output on valid box/sphere/cylinder is byte-identical to stock (the guard only triggers for a non-face replacement, which never happens for a well-formed face).

Next steps

🤖 Generated with Claude Code

gsdali and others added 2 commits June 26, 2026 07:22
… replacement

Root-caused the upstream OCCT crash behind #263 (Open-Cascade-SAS/OCCT#1322):
ShapeFix_Face::Perform casts `Context()->Apply(myFace)` to TopoDS_Face without a
type check. When an earlier fix in the shared ReShape context has replaced the face
with a COMPOUND (a self-intersecting face split into several faces), Apply() returns
a non-face; the unchecked cast builds an invalid face handle over a compound TShape
and corrupts the heap — aborting with an uncatchable OS signal (FixOrientation →
BRep_Tool::Curve → BRep_TEdge::EmptyCopy, SIGSEGV/SIGBUS at varying addresses).

Found by linking a debug-built ShapeFix_Face.cxx over the prebuilt lib: at -O0 the
bad cast throws Standard_TypeMismatch at ShapeFix_Face.cxx:383 with S.type=COMPOUND
while myFace.type=FACE.

Patch guards the cast (return early when S is not a face — the replacement is already
in the context). Validated via single-TU override-link at -O2: the bowtie reproducer
and all four crash-repro fixtures survive; ShapeFix output on valid box/sphere/cylinder
is byte-identical to stock.

Takes effect on the next xcframework rebuild; until then v1.8.3's in-wrapper
occtHasSelfIntersectingWire guard prevents the crash from reaching this code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ShapeFix_Face::Perform casts Context()->Apply(myFace) to TopoDS_Face in three
places (the FixWire block, the per-subface loop, and the NeedCheckSplitWire block),
all unguarded. The compound replacement already exists on entry to Perform (recorded
by a prior face's fix), so a single guard at the top — return early when Apply(myFace)
is not a face — covers all three. Cleaner than the per-site guard and the bowtie prism
now heals to a valid 8-face solid (was: returned the compound unchanged). Validated via
-O2 override-link; box/sphere ShapeFix output unchanged. Matches the upstream PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gsdali

gsdali commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator Author

Upstream fix submitted: Open-Cascade-SAS/OCCT#1323 (same top-of-Perform guard + a GTest regression case). When that merges and ships in an OCCT release, this carried patch can be dropped.

Rebuilds the xcframework from occt-src V8_0_0_p1 + the carried ShapeFix_Face guard
(Scripts/patches/0001). Bumps the binaryTarget URL to v1.8.4 and the checksum to the
new zip. Full suite green against the new binary (the only non-passes are the known
flaky cone STEP round-trip and a construction-layer count test — both pass in isolation
and are unaffected by the guard, which only triggers on a non-face context replacement).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gsdali gsdali marked this pull request as ready for review June 26, 2026 00:00
@gsdali gsdali merged commit c473060 into main Jun 26, 2026
@gsdali gsdali deleted the fix/263-occt-shapefix-kernel-patch branch June 26, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant