ENH: Add GradientImageFilter::SetBoundaryCondition taking a unique_ptr - #6714
Open
hjmjohnson wants to merge 2 commits into
Open
ENH: Add GradientImageFilter::SetBoundaryCondition taking a unique_ptr#6714hjmjohnson wants to merge 2 commits into
hjmjohnson wants to merge 2 commits into
Conversation
GradientImageFilter::OverrideBoundaryCondition and OptimizerParameters::SetHelper store their raw-pointer argument in a unique_ptr member, but the Python wrapping left ownership with the proxy. Both sides freed the object and the interpreter aborted at shutdown. Apply SWIGTYPE *DISOWN to both parameters and add Python regression tests.
hjmjohnson
marked this pull request as ready for review
July 27, 2026 00:02
This comment was marked as resolved.
This comment was marked as resolved.
OverrideBoundaryCondition(T *) adopts its argument in GradientImageFilter but not in the five other classes that declare the same signature, so the name alone cannot tell a caller who frees the object. Add SetBoundaryCondition(std::unique_ptr<BoundaryConditionType>), whose parameter type states the transfer, plus GetBoundaryCondition and ResetBoundaryCondition. Deprecate the owning OverrideBoundaryCondition under ITK_FUTURE_LEGACY_REMOVE and document the remaining ones as non-owning. Supersedes InsightSoftwareConsortium#4533
hjmjohnson
force-pushed
the
enh-boundary-condition-ownership-api
branch
from
July 27, 2026 00:15
7afe436 to
bafe84e
Compare
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.
GradientImageFilter::OverrideBoundaryCondition(T *)adopts its argument, but the five other classes declaring the same signature do not — so the name alone cannot tell a caller who frees the object. This addsSetBoundaryCondition(std::unique_ptr<BoundaryConditionType>), whose parameter type states the transfer, and deprecates the owning overload.Stacked on #6707 — the first commit here is that PR's. Review only
ENH: Add GradientImageFilter::SetBoundaryCondition taking a unique_ptr; this will rebase to a single commit once #6707 merges.Supersedes #4533, which stalled in 2024 on SWIG being unable to wrap a
unique_ptrparameter. That blocker is gone — see below.Why #4533's SWIG blocker no longer applies
ITK now pins SWIG 4.3.0 (
swig_version_min 4.3.0,Wrapping/Generators/SwigInterface/CMakeLists.txt:23), which shipsstd_unique_ptr.i. Verified end-to-end rather than assumed:SetBoundaryConditionmethod nodes.::std::unique_ptr<...>, not?unknown?— soigenerator.py'sskip_methodnever fires and the method reaches the.i.%unique_ptrtypemap binds: 8SWIG_POINTER_RELEASEsites in the generateditkGradientImageFilterPython.cpp.One non-obvious trap:
%unique_ptrmust be given ITK's mangled alias (itkImageBoundaryConditionIF2), not the C++ spelling. The C++ spelling fails silently — SWIG falls back to the default typemap with no error, and the only way to notice is to grep the generated C++ forSWIG_POINTER_RELEASE.Scope: the whole OverrideBoundaryCondition family
GradientImageFilterunique_ptrsetter; old overload deprecatedConstNeighborhoodIteratorNeighborhoodOperatorImageFilterVectorNeighborhoodOperatorImageFilterMorphologyImageFilterObjectMorphologyImageFilterThe rule this establishes:
OverrideBoundaryCondition(T *)never takes ownership; any owning API uses a different name and astd::unique_ptrparameter.GPUNeighborhoodOperatorImageFilter::OverrideBoundaryConditionis entirely commented out, so it is left alone as unrelated cleanup.Setter semantics: invalidation and the null guard
SetBoundaryConditionandResetBoundaryConditioncallModified(). Without it,ProcessObject::Update()short-circuits on MTime and a boundary-condition change after an initialUpdate()would silently return gradients computed with the previous condition.Modified()was added to the deprecatedOverrideBoundaryConditionas well, which has the same defect onmaintoday.SetBoundaryConditionthrows when handed an emptyunique_ptr. The boundary condition is dereferenced unconditionally —itkNeighborhoodAccessorFunctor.h:88doesboundaryCondition->operator()(...)with no null check, reached fromitkConstNeighborhoodIterator.h:208on any out-of-bounds sample — so the filter must always hold a usable one.Both were raised by Greptile on the first push and are covered by
SetBoundaryConditionModifiesFilterandSetBoundaryConditionRejectsNull.Deprecation blast radius
Audited before deprecating: exactly one in-tree owning call site (
itkGradientImageFilterTest.cxx, migrated here) and zero downstream GitHub hits forOverrideBoundaryCondition GradientImageFilter.The deprecated overload is kept under
#if !defined(ITK_FUTURE_LEGACY_REMOVE)with a\deprecatedtag, so existingnew-passing callers keep compiling and keep their ownership semantics.Test plan (all run locally)
itkGradientImageFilterOwnershipPythonTestpre-commit run --all-filesITK_LEGACY_REMOVE=OFFITK_FUTURE_LEGACY_REMOVE=ON+ITK_LEGACY_REMOVE=ONSix new GTests. Four use a destruction-counting boundary condition to observe ownership directly: the
unique_ptrsetter adopts,Get/Resetbehave, the non-owning family does not adopt, and the deprecated overload still adopts. Two more cover pipeline invalidation and the null guard.The Python test asserts
thisowntransfers onSetBoundaryCondition, that re-offering an already-adopted object raisesRuntimeErrorrather than double-freeing, and that the deprecated overload keeps its DISOWN behavior.