mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
Closing all summary cases while a delta ensemble is present crashed with a use-after-free. RicCloseSummaryCaseFeature::deleteSummaryCases holds a case list across removeCases and deletes it afterwards, while removeCases made the delta ensemble rebuild and destroy derived cases that are themselves part of that list. The previous fix rewrote the caller list with the surviving cases, which stopped the crash but left the hazard in place for any other caller holding a case list across a removal. Add RimSummaryCaseUpdateBatch, a plain scope object that is ambient for the duration of its scope. Removal now only detaches, and hands the detached cases to the batch. The outermost scope flushes, regenerating the dirty delta ensembles in dependency order first so a chained delta ensemble sees the final state of its source, then destroying the orphans with caf::PdmObjectHandleTools::deleteObjects. A nested batch contributes to the outermost one and never flushes. Orphans are held as guarded pointers, so a case the caller destroyed itself is skipped instead of being destroyed twice. Both contribution points fall back to immediate execution when no batch is active, so call sites that do not open one keep behaving as before. Open a batch in RimSummaryCaseMainCollection::removeCases and in RicCloseSummaryCaseFeature::deleteSummaryCases, which is the outermost of the two and therefore keeps the detached cases alive across its own deleteObjects call. removeCases no longer rewrites the caller list, so it now takes it by const reference.
99 lines
4.1 KiB
C++
99 lines
4.1 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2016- Statoil ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
#pragma once
|
|
|
|
#include "cafPdmChildArrayField.h"
|
|
#include "cafPdmObject.h"
|
|
#include "cafSignal.h"
|
|
|
|
#include <functional>
|
|
#include <vector>
|
|
|
|
class RimSummaryCase;
|
|
class RimFileSummaryCase;
|
|
class RimEclipseResultCase;
|
|
class RimSummaryEnsemble;
|
|
class RifSummaryCaseFileResultInfo;
|
|
|
|
//==================================================================================================
|
|
///
|
|
//==================================================================================================
|
|
class RimSummaryCaseMainCollection : public caf::PdmObject
|
|
{
|
|
CAF_PDM_HEADER_INIT;
|
|
|
|
public:
|
|
caf::Signal<> dataSourceHasChanged;
|
|
|
|
public:
|
|
RimSummaryCaseMainCollection();
|
|
~RimSummaryCaseMainCollection() override;
|
|
|
|
RimSummaryCase* summaryCase( size_t idx );
|
|
size_t summaryCaseCount() const;
|
|
|
|
std::vector<RimSummaryCase*> allSummaryCases() const;
|
|
std::vector<RimSummaryCase*> topLevelSummaryCases() const;
|
|
std::vector<RimSummaryEnsemble*> summaryEnsembles() const;
|
|
|
|
std::vector<RimSummaryCase*> createSummaryCasesFromFileInfos( const std::vector<RifSummaryCaseFileResultInfo>& summaryHeaderFileInfos,
|
|
bool readStateFromFirstFile,
|
|
bool showProgress = false );
|
|
|
|
RimSummaryCase* findTopLevelSummaryCaseFromFileName( const QString& fileName ) const;
|
|
|
|
void addCases( const std::vector<RimSummaryCase*> cases );
|
|
void addCase( RimSummaryCase* summaryCase );
|
|
void removeCase( RimSummaryCase* summaryCase, bool notifyChange = true );
|
|
// Open a RimSummaryCaseUpdateBatch around this call if the case list is used afterwards, see removeCases()
|
|
void removeCases( const std::vector<RimSummaryCase*>& cases );
|
|
void moveCase( RimSummaryCase* summaryCase, int destinationIndex );
|
|
|
|
RimSummaryEnsemble* addEnsemble( const std::vector<RimSummaryCase*>& summaryCases,
|
|
const QString& coolectionName,
|
|
bool isEnsemble,
|
|
std::function<RimSummaryEnsemble*()> allocator = defaultAllocator );
|
|
void removeEnsemble( RimSummaryEnsemble* ensemble );
|
|
void addEnsemble( RimSummaryEnsemble* ensemble );
|
|
void moveEnsemble( RimSummaryEnsemble* ensemble, int destinationIndex );
|
|
|
|
void loadAllSummaryCaseData();
|
|
|
|
QString uniqueShortNameForCase( RimSummaryCase* summaryCase );
|
|
|
|
void updateAutoShortName();
|
|
void onProjectBeingSaved();
|
|
|
|
void updateEnsembleNames();
|
|
|
|
private:
|
|
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
|
|
|
|
void initAfterRead() override;
|
|
|
|
static void loadSummaryCaseData( const std::vector<RimSummaryCase*>& summaryCases, bool extractStateFromFirstCase );
|
|
static void loadFileSummaryCaseData( const std::vector<RimFileSummaryCase*>& fileSummaryCases, bool extractStateFromFirstCase );
|
|
static RimSummaryEnsemble* defaultAllocator();
|
|
|
|
void onCaseNameChanged( const SignalEmitter* emitter );
|
|
|
|
private:
|
|
caf::PdmChildArrayField<RimSummaryCase*> m_cases;
|
|
caf::PdmChildArrayField<RimSummaryEnsemble*> m_ensembles;
|
|
};
|