Fix crashes reported by crash telemetry

* Recompute well cell arrays when the grids change

computeWellCellsPrGrid() returned early whenever the arrays had been computed once, so the
size check below it was unreachable and a stale array was kept when the grids changed. The
too-short array triggered an assert in RivReservoirViewPartMgr::computeNativeVisibility.

Return early only when the cached arrays still match the current set of grids.

* Guard against missing GUI application when applying style sheet

RiaGuiApplication::instance() does a dynamic_cast and returns null outside a GUI context. The
assert guarding this is compiled out in release, so the null pointer was dereferenced.

* Guard against missing case in flow characteristics plot field change

The case field can be set to nothing from the UI. RimEclipseResultCase::defaultFlowDiagSolution()
and reservoirViews() were then called on a null pointer.

* Guard against missing case and out of range time steps when updating flow characteristics plot

onLoadDataAndUpdate() dereferenced the case without checking, although the same function handles
a missing case further down. The time step indices come from the flow diagnostics solution, and
were used to index arrays sized by the number of case time steps without a range check.
This commit is contained in:
Magne Sjaastad authored and GitHub committed 2026-08-07 12:12:31 +02:00
1 parent ebf75c09a1
commit 318659e130
5 files changed
+70 -12

No files matched your search

@@ -563,9 +563,10 @@ void RimFlowCharacteristicsPlot::fieldChangedByUi( const caf::PdmFieldHandle* ch
if ( &m_case == changedField )
{
m_flowDiagSolution = m_case->defaultFlowDiagSolution();
// The case field can be set to nothing from the UI
m_flowDiagSolution = m_case() ? m_case()->defaultFlowDiagSolution() : nullptr;
m_currentlyPlottedTimeSteps.clear();
if ( !m_case()->reservoirViews().empty() )
if ( m_case() && !m_case()->reservoirViews().empty() )
{
m_cellFilterView = m_case()->reservoirViews()[0];
}
@@ -607,9 +608,15 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate()
m_currentlyPlottedTimeSteps = calculatedTimesteps;
}
std::vector<QDateTime> timeStepDates = m_case->timeStepDates();
QStringList timeStepStrings = m_case->timeStepStrings();
std::vector<double> lorenzVals( timeStepDates.size(), HUGE_VAL );
// The case can be missing, as the case field can be set to nothing from the UI
std::vector<QDateTime> timeStepDates;
QStringList timeStepStrings;
if ( m_case() )
{
timeStepDates = m_case()->timeStepDates();
timeStepStrings = m_case()->timeStepStrings();
}
std::vector<double> lorenzVals( timeStepDates.size(), HUGE_VAL );
m_flowCharPlotWidget->removeAllCurves();
@@ -660,7 +667,11 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate()
m_maxTof() );
timeStepToFlowResultMap[timeStepIdx] = flowCharResults;
}
lorenzVals[timeStepIdx] = timeStepToFlowResultMap[timeStepIdx].m_lorenzCoefficient;
// The time step indices are given by the flow diagnostics solution, and can be out of range for the case
if ( timeStepIdx >= 0 && static_cast<size_t>( timeStepIdx ) < lorenzVals.size() )
{
lorenzVals[timeStepIdx] = timeStepToFlowResultMap[timeStepIdx].m_lorenzCoefficient;
}
}
m_timeStepToFlowResultMap = timeStepToFlowResultMap;
@@ -678,6 +689,8 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate()
for ( int timeStepIdx : m_currentlyPlottedTimeSteps )
{
if ( timeStepIdx < 0 || static_cast<size_t>( timeStepIdx ) >= timeStepDates.size() ) continue;
const auto& flowCharResults = timeStepToFlowResultMap[timeStepIdx];
m_flowCharPlotWidget->addFlowCapStorageCapCurve( timeStepDates[timeStepIdx],
@@ -185,17 +185,34 @@ size_t RigEclipseCaseData::gridCount() const
return m_mainGrid->gridCount();
}
//--------------------------------------------------------------------------------------------------
/// The cached well cell arrays are indexed by grid cell index, and are only valid as long as they
/// have one array per grid sized to match the cell count of that grid.
//--------------------------------------------------------------------------------------------------
bool RigEclipseCaseData::isWellCellsPrGridUpToDate( const std::vector<RigGridBase*>& grids ) const
{
if ( m_wellCellsInGrid.size() != grids.size() ) return false;
for ( size_t gIdx = 0; gIdx < grids.size(); ++gIdx )
{
if ( m_wellCellsInGrid[gIdx].isNull() || m_wellCellsInGrid[gIdx]->size() != grids[gIdx]->cellCount() ) return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigEclipseCaseData::computeWellCellsPrGrid()
{
// If we have computed this already, return
if ( !m_wellCellsInGrid.empty() ) return;
std::vector<RigGridBase*> grids;
allGrids( &grids );
// If we have computed this already for the current set of grids, return. The cached arrays are indexed by grid
// cell index, and must be recomputed if the grids have changed after the previous computation.
if ( isWellCellsPrGridUpToDate( grids ) ) return;
// Debug code used to display grid names and grid sizes
/*
size_t totCellCount = 0;
@@ -130,6 +130,7 @@ public:
private:
void computeActiveCellIJKBBox();
void computeWellCellsPrGrid();
bool isWellCellsPrGridUpToDate( const std::vector<RigGridBase*>& grids ) const;
void computeActiveCellsGeometryBoundingBoxSlow();
void computeActiveCellsGeometryBoundingBoxOptimized();
@@ -84,6 +84,30 @@ TEST( RigGridManager, EqualTests )
EXPECT_TRUE( existingGrid.notNull() );
}
//--------------------------------------------------------------------------------------------------
/// The well cell arrays are cached, and must be recomputed if the grid changes size after the first
/// computation. A stale array is shorter than the cell count of the grid it is used with.
//--------------------------------------------------------------------------------------------------
TEST( RigEclipseCaseDataTest, WellCellsInGridIsRecomputedWhenGridSizeChanges )
{
cvf::ref<RigMainGrid> mainGrid = new RigMainGrid;
mainGrid->setCellCounts( cvf::Vec3st( 2, 2, 2 ) );
cvf::ref<RigEclipseCaseData> eclipseCase = new RigEclipseCaseData( nullptr );
eclipseCase->setMainGrid( mainGrid.p() );
const cvf::UByteArray* wellCells = eclipseCase->wellCellsInGrid( 0 );
ASSERT_TRUE( wellCells != nullptr );
EXPECT_EQ( mainGrid->cellCount(), wellCells->size() );
// Grow the grid after the well cell arrays have been cached
mainGrid->setCellCounts( cvf::Vec3st( 3, 3, 3 ) );
wellCells = eclipseCase->wellCellsInGrid( 0 );
ASSERT_TRUE( wellCells != nullptr );
EXPECT_EQ( mainGrid->cellCount(), wellCells->size() );
}
/*
//--------------------------------------------------------------------------------------------------
@@ -381,10 +381,13 @@ bool RiuGuiTheme::applyStyleSheet( RiaDefines::ThemeEnum theme )
{
if ( styleSheetFile.open( QIODevice::ReadOnly ) )
{
RiaGuiApplication* app = RiaGuiApplication::instance();
QString styleSheet = styleSheetFile.readAll();
QString styleSheet = styleSheetFile.readAll();
preparseStyleSheet( theme, styleSheet );
app->setStyleSheet( styleSheet );
if ( RiaGuiApplication* app = RiaGuiApplication::instance() )
{
app->setStyleSheet( styleSheet );
}
}
return true;
}