Skip to content

Fix off-by-one bounds checks of the Python wrapper matrix views - #2962

Open
KRGulaj wants to merge 2 commits into
su2code:developfrom
KRGulaj:fix_pywrapper_matrix_view_bounds
Open

KRGulaj wants to merge 2 commits into
su2code:developfrom
KRGulaj:fix_pywrapper_matrix_view_bounds

Conversation

@KRGulaj

@KRGulaj KRGulaj commented Oct 6, 2026

Copy link
Copy Markdown

Proposed Changes

The Python matrix views check zero-based indices with index > extent. The first index past the end passes this check. For example, driver.Solution(iSolver)(0, nVar) returns the first value of the next row and gives no error. A row index equal to the number of rows reads or writes past the end of the buffer. On a marker view it causes a segmentation fault.

This PR changes > to >= in the three Access functions of CPyWrapperMatrixView.hpp. All Get, Set and operator() forms use these functions. Valid indices work as before. No solver path uses the views, so results do not change.

I added my name to AUTHORS.md.

Related Work

No issue. I found the defect when I used the Python wrapper.

PR Checklist

  • I am submitting my contribution to the develop branch.
  • My contribution generates no new compiler warnings (try with --warnlevel=3 when using meson).
  • My contribution is commented and consistent with SU2 style (https://su2code.github.io/docs_v7/Style-Guide/).
  • I used the pre-commit hook to prevent dirty commits and used pre-commit run --all to format old commits.
  • I have added a test case that demonstrates my contribution, if necessary. Not added: SU2_MPI::Error ends the process, so a unit test cannot catch the error.
  • I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp), if necessary. Not applicable: no option or interface changes.

Tests

  • A script reads and writes each view with the first index past the end, in every dimension, one access per process. Before: 7 of 10 accesses returned or changed another element, 2 read past the buffer, 1 crashed. After: all 10 give the "out of bounds" error. The last valid index in every dimension and the list forms of the correct length return the values that were set, before and after. Serial and 2 MPI ranks.
  • GCC with --warnlevel=3: primal and adjoint, with and without MPI, no new warnings.
  • clang-cl on Windows: primal and adjoint build.
  • The regression scripts and unit tests pass in SU2's CI Docker images. The results are identical to develop.

The element access of CPyWrapperMatrixView, CPyWrapperMarkerMatrixView and
CPyWrapper3DMatrixView checks zero-based indices with "index > extent", so
the first index past the end passes the check. For example,
driver.Coordinates()(nPoint, 0) or Solution(iSolver)(0, nVar) returns data
instead of raising the "out of bounds" error:
- a column index equal to the number of columns reads or writes the first
  element of the next row (Set with a list one value too long does the same);
- a row index equal to the number of rows reads or writes past the end of
  the buffer;
- for the marker views, a vertex index equal to the number of vertices
  dereferences a pointer past the vertex array and crashes.

Compare with ">=" in the three const Access functions. The non-const Access
functions and every Get/Set/operator() of the views go through them, so
this covers all entry points.

Results do not change: valid indices pass the check as before, and no
solver path uses these views.
@bigfooted

Copy link
Copy Markdown
Contributor

Thanks, do you have a testcase that failed and now passes because of the fix, and that can be added to the regression tests?

@KRGulaj

KRGulaj commented Oct 7, 2026

Copy link
Copy Markdown
Author

Thanks. Not yet, because SU2_MPI::Error ends the process, so a unit test cannot catch the error. I can add a py_wrapper regression test: it runs a few iterations of a small case, then accesses each view with the first index past the end in a separate process and checks that this process stops with the "out of bounds" error. The last valid index must still return the value that was set. On develop the test fails, because these accesses return data without an error. With the fix it passes. I would add it to serial_regression.py. Is that ok for you?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants