Skip to content

Cyclic delta ensemble sources stack-overflow in ensemble name generation #14519

Description

@magnesj

Making two delta ensembles refer to each other stack-overflows in ensemble name generation. Reproduced on dev as SEH exception with code 0xc00000fd from a unit test doing nothing but deltaA->setEnsemble1( deltaB ) after deltaB was already sourced from deltaA.

The loop

Name propagation is a cycle that normally terminates only by reaching a fixed point:

  • RimSummaryEnsemble::updateName ends in caseNameChanged.send() (RimSummaryEnsemble.cpp:320), guarded by if ( m_name == candidateName ) return; at :317.
  • RimSummaryCaseMainCollection connects that signal to onCaseNameChanged for every ensemble (RimSummaryCaseMainCollection.cpp:337, :466).
  • onCaseNameChanged (:680) calls RiaSummaryTools::updateSummaryEnsembleNames(), which calls updateEnsembleNames() (:871), which calls updateName() on every ensemble.

The guard at :317 is the only termination condition. For a delta ensemble, nameKeys() (RimDeltaSummaryEnsemble.cpp:229) is built from m_ensemble1->name() and m_ensemble2->name(), so with A sourced from B and B sourced from A each pass feeds the other a longer name and the fixed point is never reached. The duplicate-name suffixing at RimSummaryEnsemble.cpp:304-314 accelerates it — observed names grow like Delta: Delta: <...> (subset-1) - <...> (subset-1) until the stack runs out.

Trigger

RimDeltaSummaryEnsemble::setEnsemble1/setEnsemble2 (:106, :116) call RiaSummaryTools::updateSummaryEnsembleNames() directly, so the overflow happens inside the setter that closes the cycle. calculateValueOptions excludes only this from the source ensemble options, so the second half of a cycle is offered in the UI. RicNewDerivedEnsembleFeature bypasses the setters and assigns the fields directly, which avoids the overflow but still builds the cycle.

Fix

Refuse the assignment when it would make the dependency graph cyclic, in setEnsemble1()/setEnsemble2() and in the options offered by calculateValueOptions. RimSummaryEnsembleTools::wouldCreateDependencyCycle(), added in #14518, answers exactly that question and is already cycle-safe itself.

Independent of #14517 and #14518 — the traversal fixed there terminates on a cycle, this one does not. The regression test DependencyOrder_CycleTerminates added in #14518 closes its cycle by writing the PdmPtrField directly rather than through the setter, specifically to avoid this overflow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions