Repository navigation
Meta: hardening pass - exception safety, container correctness, and object-model safety #763
Description
Purpose
This issue is the coordination index for the current hardening work. Several PRs are stacked or touch the same legacy containers and path implementation files.
Detailed design and review discussion belongs in each pull request. This issue tracks dependency order, readiness, and merge progress. Status refreshed on 2026-10-07. Each line states whether a PR is merged or still open; the 19 follow-ups below include six dependent drafts. Passing checks and a clean merge status do not imply review approval. Recheck conflicts after every merge.
Working rules
- Review dependent PRs before prerequisites merge if useful, but merge only after their prerequisites are integrated and the branch is refreshed and validated.
- After a prerequisite merges, refresh its direct child from
master, rerun focused validation, and update this checklist. - Review overlapping
SoPathchanges sequentially even when they are logically independent.
Dependency map
SbHash: #750 (merged) -> #751 (merged) -> #752 (merged) -> #753 (merged) -> #754 (merged) -> #755
GL: #756 (merged) -> #757 (merged) -> #758
Bump: #759 (merged) -> #760 (merged)
OOM: #769 + #770 -> #771 -> #772
#754 -------> #772
#770 is independent of #769 in Git history. #771 includes both prerequisite histories. #772 includes #771 and now #754; it should merge after both. #758 depends only on #757. The final #760 scope has no dependency on #755 or #758.
SbHash stack
- Fix SbHash self-assignment #750 - self-assignment fix; merged
- Fix SbHash mutable iterator traversal #751 - mutable iterator traversal; merged
- Fix SbHash statistics calculation #752 - statistics; merged
- Define the SbHash noexcept hash contract #753 - non-throwing hash contract; merged into
master - Relink SbHash entries during resize #754 - relink during resize; merged into
master. Its ABI suppression rules remain separate from Use SbSmallMap for small GL context caches #758's file. - Defer SbHash storage allocation #755 - lazy storage; open, non-draft; contains refreshed Relink SbHash entries during resize #754; no merge conflicts against current
master; checks passed. ItsSbHash.hchanges still overlap with Harden cc_memalloc alignment, growth and allocation failures #770/Handle cc_dict limits and allocation failures in core callers #771 and will need semantic reconciliation if that OOM stack merges first.
SbList, SbSmallMap, and GL-context stack
- Make SbList growth exception safe #756 -
SbListgrowth and fit exception safety; merged - Add SbSmallMap for the profiler texture cache #757 - profiler texture
SbSmallMap; merged - Use SbSmallMap for small GL context caches #758 - small GL-context caches; open, non-draft; prerequisite merged; no merge conflicts; checks passed
- Fix SoShape bump programs across GL cache contexts #759 - bump-program context lifecycle; merged
- Reduce bump renderer allocations #760 - reduce bump renderer allocations; merged with its narrowed final scope
- Make SbPList growth exception safe #740 - related but independent
SbPListgrowth exception safety; merged
SoPath and object-model hardening
These fixes are mostly independent in intent but overlap in SoPath and related implementation files. Review the remaining PRs sequentially from master and recheck conflicts after each merge.
- Fix SoPath/SoFullPath downcast undefined behavior across the codebase #714 - safe full-path view and removal of invalid
SoPathtoSoFullPathdowncasts; merged - Validate SoPath child appends in all builds #742 - validate child appends; merged
- Validate legacy SoPath accessor bounds in all builds #743 - validate legacy accessor bounds; merged
- Harden SoPath range and stack operations in all builds #744 - harden range and stack operations; merged
- Guard SoTempPath::replaceTail() on empty paths #745 - guard empty
SoTempPath::replaceTail(); merged - Preserve SoTempPath policy when appending to empty paths #746 - preserve
SoTempPathpolicy when appending to an empty path; merged intomaster - Restore safe SoNodeKitPath object semantics #747 - restore safe
SoNodeKitPathobject semantics; merged intomaster - Fix SoPath assignment auditor lifecycle #748 - assignment auditor lifecycle; merged
- Validate SoPath auditor callbacks in all builds #749 - auditor callback validation; merged
The #746 and #747 regression registrations live in separate files under testsuite/regressions/, loaded by RegressionTests.cmake; both are now in master.
Resolved prerequisites
- Use SbString for SoInput numeric parsing buffer #736 -
SoInput_FileInfobuffer migrated toSbString; merged, and Clear the SoInput real-number parsing buffer #737 was refreshed frommaster - Fix SbList removal of missing items #738 - missing-item removal in
SbList; merged, and Make SbList growth exception safe #756 was refreshed frommaster
Independent and OOM PRs
- Fix -Wundef debug-diagnostic bugs in SoField and SoVRMLGroup #677 - debug diagnostic configuration; merged
- Harden SbHeap edge-case handling #724 -
SbHeapedge cases; merged - Harden cc_heap removal, duplicates, and growth #725 -
cc_heaparbitrary removal and duplicates; merged - Harden cc_dict resizing and hash changes #726 -
cc_dictresize and hash changes; merged - Clear the SoInput real-number parsing buffer #737 - clear the real-number parsing buffer; merged
- Restore CoinTests run_test filtering #739 - restore
CoinTestscommand-line filtering; merged - Add robust three-plane intersection #761 - robust three-plane intersection; independent, open, non-draft; no merge conflicts; checks passed
- Remove unreachable return in SoLevelOfDetail and test bounding-box traversal #765 -
SoLevelOfDetailbounding-box traversal; independent, open, non-draft; no merge conflicts; checks passed - Support control-point color interpolation on NURBS surfaces #767 - NURBS control-point colors; independent draft design now ready for review, open, non-draft; no merge conflicts; checks passed
- Remove Windows 9x font workarounds and deprecated version queries #768 - remove Windows 9x font workarounds; independent, open, non-draft; no merge conflicts; checks passed; platform-policy change requires review
- Relink cc_dict entries and preserve state on resize allocation failure #769 - relink
cc_dictentries on resize; open, non-draft; no merge conflicts; checks passed - Harden cc_memalloc alignment, growth and allocation failures #770 - harden
cc_memalloc; open, non-draft; independent of Relink cc_dict entries and preserve state on resize allocation failure #769 in Git history; no merge conflicts; checks passed - Handle cc_dict limits and allocation failures in core callers #771 - harden
cc_dict; open, non-draft; depends on Relink cc_dict entries and preserve state on resize allocation failure #769 and Harden cc_memalloc alignment, growth and allocation failures #770; no merge conflicts; checks passed - Handle OOM in cc_dict consumers and supporting primitives #772 - handle OOM in dictionary consumers; open, non-draft; depends on Relink cc_dict entries and preserve state on resize allocation failure #769, Harden cc_memalloc alignment, growth and allocation failures #770, Handle cc_dict limits and allocation failures in core callers #771, and merged Relink SbHash entries during resize #754. Refresh against current
masterand recheck mergeability before integration. ItsSbHash::resize()combines Relink SbHash entries during resize #754's non-throwing relink with allocation-failure handling.
Next merge steps
- Define the SbHash noexcept hash contract #753 and Relink SbHash entries during resize #754 are merged. Refresh Defer SbHash storage allocation #755 and Handle OOM in cc_dict consumers and supporting primitives #772 from current
masterbefore their merges; review Use SbSmallMap for small GL context caches #758 independently. - Merge Relink cc_dict entries and preserve state on resize allocation failure #769 and Harden cc_memalloc alignment, growth and allocation failures #770 before Handle cc_dict limits and allocation failures in core callers #771; merge Handle cc_dict limits and allocation failures in core callers #771 before Handle OOM in cc_dict consumers and supporting primitives #772. The Relink SbHash entries during resize #754/Handle OOM in cc_dict consumers and supporting primitives #772 integration was tested in the lab, but Handle OOM in cc_dict consumers and supporting primitives #772 still needs a final refresh after its remaining prerequisites merge.
- Resolve the remaining Defer SbHash storage allocation #755 overlap with Harden cc_memalloc alignment, growth and allocation failures #770/Handle cc_dict limits and allocation failures in core callers #771 according to merge order. Its current clean status is only against
master. - Preserve SoTempPath policy when appending to empty paths #746 and Restore safe SoNodeKitPath object semantics #747 are merged. After any further overlapping path PR merges, refresh and validate the remaining path PRs.
- The test-registration conflicts in Remove unreachable return in SoLevelOfDetail and test bounding-box traversal #765, Remove Windows 9x font workarounds and deprecated version queries #768, and Harden cc_memalloc alignment, growth and allocation failures #770–Handle OOM in cc_dict consumers and supporting primitives #772 were reconciled on 2026-10-03 by moving PR-specific registrations under
testsuite/regressions/. Recheck those integrations as prerequisites merge. Handle cc_dict limits and allocation failures in core callers #771/Handle OOM in cc_dict consumers and supporting primitives #772 may also overlap with Restore safe SoNodeKitPath object semantics #747 in NEWS after Restore safe SoNodeKitPath object semantics #747 merges.
Current integration lab (2026-10-07)
lab/open-prs-integration at 48423165217c17abc2dddae8b0878c15a354a7b5 contains master fc2d9cc256b591160b916290fe4fe442ae128790 plus the exact heads of all 32 currently open PRs (30 from Dikluwe and two external). All 19 follow-ups #775–#793 are included. The head is published on the Dikluwe fork. Linux Debug shared and Release static builds in RAM each passed 120/120 CTests. Conflict resolutions exist only in the lab merges; PR heads were unchanged.
Submission order: 19 CC/Sb follow-ups (updated 2026-10-07)
These are the 19 original local codex/pre-pr/* candidates. All have now been submitted as PRs. #775–#787 are ready for review; #788–#793 remain drafts because they carry explicitly declared prerequisite histories. The numbers preserve the planned dependency order. Refresh stacked drafts after prerequisites merge, then request review of their own remaining diffs. As of 2026-10-07, all six dependent drafts are mergeable against current master and each passed 9/9 CI checks; #793 required an ABI preservation follow-up (f623dfaf13) before that result.
Group 1 — independent fixes and test infrastructure
codex/pre-pr/bump-fixture-static— PR #775, isolated static-test fixture correction; land before branches whose static tests use it.codex/pre-pr/sbheap-cancel-contract— PR #776, isolated contract documentation; CI passed, including Windows.codex/pre-pr/sblist-value-bounds— PR #777, after the already merged Make SbList growth exception safe #756; CI passed, including Windows.codex/pre-pr/sbplist-bounds— PR #778, after the already merged Make SbPList growth exception safe #740; CI passed, including Windows.codex/pre-pr/callback-list-copy-stress— PR #779, focused copy/lifetime regression; CI passed, including Windows.codex/pre-pr/profiler-stats-lifetime— PR #780, profiler action-data lifetime and insertion ownership; CI passed, including Windows.
Group 2 — containers and dictionaries
codex/pre-pr/cc-list-bounds— PR #786, isolated bounds delta; refresh after OOM stack through Handle OOM in cc_dict consumers and supporting primitives #772.codex/pre-pr/cc-dict-complete— draft PR #789, stacked on Define the SbHash noexcept hash contract #753, Relink SbHash entries during resize #754 and Relink cc_dict entries and preserve state on resize allocation failure #769–Handle OOM in cc_dict consumers and supporting primitives #772 plus fixture Fix duplicate bump fixture global in static builds #775; refresh after prerequisites merge.codex/pre-pr/cc-hash-complete— draft PR #790, stacked on Complete cc_dict hash exception and capacity contracts #789; refresh after the shared prime helper lands.codex/pre-pr/sbdict-complete— draft PR #791, stacked on Complete cc_dict hash exception and capacity contracts #789; refresh aftercc_dictcompletion.codex/pre-pr/sbhash-complete— draft PR #792, stacked on Define the SbHash noexcept hash contract #753–Defer SbHash storage allocation #755, Relink cc_dict entries and preserve state on resize allocation failure #769–Handle OOM in cc_dict consumers and supporting primitives #772 and fixture Fix duplicate bump fixture global in static builds #775; remove duplicate shared prime helper after Complete cc_dict hash exception and capacity contracts #789 lands.codex/pre-pr/sbsmallmap-complete— PR #781, isolated type contract and failure coverage; CI passed, including Windows. The static fixture is tracked separately in Fix duplicate bump fixture global in static builds #775.
Group 3 — map consumers and rendering
codex/pre-pr/glglue-lifetime-complete— PR #787, own lifetime delta; lab preserved Handle OOM in cc_dict consumers and supporting primitives #772 OOM insertion check, refresh this line after Handle OOM in cc_dict consumers and supporting primitives #772 merges.codex/pre-pr/gl-contexts-small-complete— draft PR #793, stacked on Use SbSmallMap for small GL context caches #758, Complete SbSmallMap equality contract and failure coverage #781 and fixture Fix duplicate bump fixture global in static builds #775; refresh to retain only the GL context follow-up.codex/pre-pr/action-apply-exceptions— PR #782, isolated action state restoration; CI passed, including Windows.codex/pre-pr/gl-render-exceptions— draft PR #788, stacked on #782. Pure master fails its GL regression (80/81); stack with Restore SoAction state when traversal throws #782 passes (82/82), as does the lab (107/107). Refresh after Restore SoAction state when traversal throws #782 merges.
Group 4 — overlapping bump-cache changes, sequentially
codex/pre-pr/bump-cache-ready-path— PR #783, ready path first; CI passed, including Windows.codex/pre-pr/bump-cache-diagnostics-memory— PR #784, own diff; merge after Avoid bump diagnostic setup on ready cache requests #783, then refresh. CI passed, including Windows.codex/pre-pr/bump-shared-programs— PR #785, own diff; merge after Avoid bump diagnostic setup on ready cache requests #783 and Reduce bump cache diagnostic memory #784. Combined lab gate resolved initializer and diagnostic test expectation; carry resolution into Share validated bump programs across renderers #785 after prerequisites land. CI passed, including Windows.
The two SCXML alias branches belong to the separate XML workstream and are outside this CC/Sb submission queue.
Publication gate for each item: transport the current head to Windows and record its result; refresh a PR branch on its actual target master; verify that its PR diff contains only its own contribution (and the explicitly stated prerequisite history for a stacked draft); compile and run focused and full tests on that target. Also validate the candidate in a separate temporary lab/teste/<topic> worktree against the fixed lab/open-prs-integration composition recorded in docs/CONTROLE_BRANCHES.md, using RAM for builds. Record base/change SHAs, commands and results, fix and repeat on failure, then remove the temporary copy. Open as draft after these gates, then request review when ready.
XML and SCXML PR family (2026-10-07)
This is a separate workstream from the 19 CC/Sb follow-ups above. Independent changes are open and ready for review: #794, #795, #797–#803, and #804–#808. The #804 SARIF-upload failure was transient: an empty commit reran CI without changing the tree or PR diff, and all 9/9 checks now pass (ABI, CodeQL, and all platform jobs). Ready for review does not imply maintainer approval.
Dependent drafts and merge order:
| Sequence | Draft | Refresh after prerequisite merges |
|---|---|---|
| #795 → #796 | Bundled Expat 2.9.0; #795 selects the matching header | Remove #795 history from the #796 diff |
| #808 → #809 | DOM comparison, null CDATA regression, ASan/UBSan/libFuzzer harness | Retain only the #809 contribution |
| #801 → #810 → #811 | Length guard, then opt-in parser resource limits | Refresh each direct child in order; retain only its own contribution |
The three new drafts #809–#811 were tested both on their declared stacked destination histories and in separate temporary cumulative lab worktrees. Full Linux CTest totals: #809 85/85 (stack) and 124/124 (lab), #810 86/86 and 124/124, #811 87/87 and 125/125. #809 also passed a 100-run Clang/ASan/UBSan/libFuzzer smoke. All builds were in RAM. Remote CI has now passed 9/9 checks on each draft (ABI, CodeQL, Ubuntu, Windows, and macOS). The local-only lab/open-prs-integration now ends at 4944c772ed066453a89da8acb35cea64ccf498e1; this newer XML integration head was not pushed to the fork. Recheck conflicts and CI after each prerequisite merge.
Base and data structures: candidates 14–21 published (2026-10-09)
These eight follow-ups are now submitted. All remain open. #827 and #831 are ready for review; the other six remain drafts because they include prerequisite histories. Ready for review and passing CI do not imply maintainer approval.
| Candidate | PR and scope | Status | Direct prerequisites |
|---|---|---|---|
| 14 | #825 — abort safely on cc_rbptree node allocation failure |
Draft | #772 |
| 15 | #826 — safe traversal when callbacks mutate auditors | Draft | #772, #813 |
| 16 | #827 — cleanup registration lifetime and reentrant shutdown | Ready for review | Independent |
| 17 | #828 — atomic standard-stream initialization and descriptor ownership on failure | Draft | #827 |
| 18 | #829 — handle unavailable standard streams in consumers | Draft | #828 |
| 19 | #830 — sticky read-error status and compressed errors distinguished from EOF | Draft; ABI check requires review | #829 |
| 20 | #831 — preserve callback-list state when insertion throws | Ready for review | Independent |
| 21 | #832 — strong exception guarantee for callback-list copy and assignment | Draft | #831 |
Dependency and refresh order
#772 ------------> #825
#772 + #813 ------> #826 ------> #823 (existing draft)
#827 ------------> #828 ------> #829 ------> #830
#831 ------------> #832
#823 now explicitly declares #826 as a prerequisite. After each prerequisite merges, refresh its direct child from master, retain its own contribution, rerun focused and full validation, and recheck conflicts. Keep #830 in draft until its prerequisite and ABI review are resolved.
Validation at the published heads
- Abort safely when cc_rbptree node allocation fails #825, Keep cc_rbptree traversal safe when callbacks mutate auditors #826, Keep Coin cleanup registration valid across reentrant shutdown #827, Initialize Coin standard streams atomically and preserve descriptors on failure #828, Handle unavailable Coin standard streams in IO, profiling and vector output #829, Preserve SoCallbackList state when callback insertion throws #831 and Give SoCallbackList copy and assignment a strong exception guarantee #832 passed all remote CI checks, including Ubuntu, Windows and macOS with both renderer configurations, libabigail and CodeQL.
- Expose sticky SoInput read errors and distinguish compressed failures from EOF #830 at
0e549ee73e2d951d140eecb6098416430b56d6c1passed all six platform jobs and both CodeQL checks. Its libabigail job failed withabidiffstatus 12; this is an outstanding formal gate. - That ABI report flags reference-to-pointer XML signatures in
cc_xml_doc_get_filter_cbandcc_xml_doc_write_to_buffer, already changed by upstream Make XML C headers C-compatible #764 (c973e1dd3d). Expose sticky SoInput read errors and distinguish compressed failures from EOF #830's XML source and headers matchmaster. A client compiled with the original v4.0.10 XML headers successfully exercised those legacy calls against the candidate library. This is evidence for review, not a passing ABI check; no public-API suppression was added. - The Expose sticky SoInput read errors and distinguish compressed failures from EOF #830 runtime-library discovery fix adds versioned
libbz2.so.1.0/libbz2.so.1names. A control rejecting unversioned library names failed with the previous glue and passed with the fix. - The Windows fixes keep the throwing traversal fixture's MSVC exception setting confined to its test target and make the cleanup fixture observe public APIs instead of referencing an unexported private function.
The final local cumulative publication lab is lab/open-prs-integration at d7f08bae8c9b0091789474b334a3dca81de3be3e: 35/35 focused tests and 153/153 full CTests, no skips, using a RAM build (GCC/Ninja, Debug shared, COIN_THREADSAFE=ON, external Expat, Xvfb/software GLX). This local lab head was not pushed to the fork and does not represent upstream integration. Earlier lab sections above retain their dated snapshots.
The original 21-contribution Base/data-structure queue is now published as #812–#832. The six font candidates remain unpublished and depend on #774; they are outside this publication batch.
Activity
veelo commentedon Sep 30, 2026
Thank you for your work and for the tokens. At this stage I think further merges halt on resolving conflicts and taking PRs out of draft. I'll keep an eye on updates.
veelo commentedon Sep 30, 2026
It appears that the moment I merge one PR, all other PRs start reporting conflicts. I think we might need to iterate them one by one. I have approved #743 so if you could resolve that one once more then I can merge it. After that we can proceed with #744. You can also take #751 out of draft mode, if you are happy with its state.