Skip to content

WellConnections: bound the Cartesian->compressed lookup - #1053

Open
hnil wants to merge 1 commit into
OPM:masterfrom
hnil:pr/wellconnections-lgr-safety
Open

WellConnections: bound the Cartesian->compressed lookup#1053
hnil wants to merge 1 commit into
OPM:masterfrom
hnil:pr/wellconnections-lgr-safety

Conversation

@hnil

@hnil hnil commented Jul 29, 2026

Copy link
Copy Markdown
Member

Narrowed after review — this is now only the out-of-bounds read. The LGR-specific handling and its test have been dropped; see the discussion below.

What

WellConnections::init translates each connection into a compressed cell index:

cart_grid_idx = i + nx*(j + ny*k);
compressed_idx = cartesian_to_compressed[cart_grid_idx];

and does the same for possibleFutureConnections. Neither lookup checks that the computed position is inside cartesian_to_compressed before indexing it.

The map is sized by the level-zero Cartesian grid, and a connection is not obliged to carry a position in that grid. When the position lands past the end, that is an out-of-bounds read during load balancing.

The change

Both lookups go through a helper that returns −1 for a position outside the map. −1 then flows into the existing "ignore connections in inactive cells" test — no new control flow, and no new notion of a skipped connection: out-of-map is handled exactly as inactive already is.

The bound is cartesian_to_compressed.size(), i.e. the container actually being indexed, rather than the product of cartesianSize. The two agree in the CpGrid constructor, but the four-argument constructor takes them independently, so bounding against the container is the honest check.

Nothing changes for a position that was already in range, so grids whose connections all address level zero are unaffected.

On the review comments

it is 10 steps ahead of our schedule and we should first make the simple cases work

Understood, and dropped accordingly. The previous version also skipped connections by refinement level, which is a modelling decision about what belongs in the level-zero well graph. That is the part that was ahead of schedule, and it is gone — nothing here depends on refinement any more.

Some of this code is more dangerous than before

Fair on the earlier version: it introduced a second, silent reason for a connection to disappear from the well graph, including for ordinary level-zero connections, with no diagnostic. This version does not add a skip path at all — it reuses the inactive-cell one — so the only behavioural difference is that a read which was undefined now returns −1.

Testing

test_graphofgrid and the zoltan/partition tests pass. Built against opm-common master.

No unit test is included: the defect is an out-of-bounds read, and the value it returns is unspecified, so an assertion on the result is not decisive. It is visible under a sanitizer build. Happy to add an ASan-guarded case if you would like one.

Not needed by anything in flight

For scheduling: none of the opm-common or opm-simulators PRs currently open depend on this. Pending it costs nothing on my side — say the word and I will close it and carry the fix locally.

@hnil
hnil requested review from aritorto and blattms July 29, 2026 09:43
@hnil hnil added the manual:bugfix This PR is a bug fix and should be noted in the manual label Jul 29, 2026

@blattms blattms left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot. While this is generally appreciated it is 10 steps ahead of our schedule and we should first make the simple cases work.

Some of this code is more dangerous than before. Probably a symptom of coding agents just somehow making things work ...

@hnil

hnil commented Jul 29, 2026

Copy link
Copy Markdown
Member Author

Context for reviewers: this is part of a group of independent LGR fixes, none of which depend on each other to build or merge.

Closest relatives:

@hnil

hnil commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

On more contest is: we have a prototype LGR implementation which can produce results for some case. This make it possible to fix a lot of output issues and infrastructure problems.. The idea is that fixing all this outputs now will be usefull both for getting the new code work and be able to use the prototype. The idea for the opm-grid requests was to make the changes need in opm-common and opm-simulators possible, but also some of the bugs found.

@hnil hnil changed the title WellConnections: do not index the level-zero map with LGR-local positions WellConnections: bound the Cartesian->compressed lookup Jul 30, 2026
@hnil
hnil force-pushed the pr/wellconnections-lgr-safety branch from f7584b7 to 8e5aede Compare July 30, 2026 09:12
@hnil

hnil commented Jul 30, 2026

Copy link
Copy Markdown
Member Author

Thanks — both points taken, and I've narrowed this to just the out-of-bounds read.

The refinement-level handling is gone. You're right that it was a modelling decision about what belongs in the level-zero well graph, and that isn't this PR's business. It also introduced a second, silent way for a connection to vanish from the graph — including ordinary level-zero ones — which is a fair reading of "more dangerous". What's left adds no skip path at all: an out-of-map position returns -1 and flows into the existing inactive-cell test, so the only behavioural change is that a read which was undefined now isn't.

I also moved the bound from the product of cartesianSize to cartesian_to_compressed.size() — the container actually being indexed. Those agree in the CpGrid constructor but not necessarily in the four-argument one.

On scheduling: nothing I have open in opm-common or opm-simulators depends on this, so there's no pressure from my side. Happy to park it if you'd rather not touch this path yet — just say so and I'll close it and carry the fix locally until the simple cases are where you want them.

@hnil

hnil commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

What should I do with this? @blattms. It fix a bug and run all tests.

WellConnections::init translates each well connection into a compressed cell
index with

    cart_grid_idx = i + nx*(j + ny*k);
    compressed_idx = cartesian_to_compressed[cart_grid_idx];

and does the same for possibleFutureConnections.  Neither lookup checked that
the computed position is inside cartesian_to_compressed before indexing it.

The map is sized by the level-zero Cartesian grid, and a connection is not
obliged to carry a position in that grid -- a completion inside a local grid
refinement, for instance, carries a position local to the refined grid.  When
that position lands past the end of the map the result is an out-of-bounds read
during load balancing.

Route both lookups through a helper that returns -1 for a position outside the
map, which the existing "ignore inactive cells" test already handles.  Nothing
changes for a position that was in range, so grids whose connections all
address level zero are unaffected.
@hnil
hnil force-pushed the pr/wellconnections-lgr-safety branch from 8e5aede to c347ec4 Compare August 19, 2026 07:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual:bugfix This PR is a bug fix and should be noted in the manual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants