la::MatrixCSR: moved-from matrix retains its MPI_Request

Open
#4,529 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
cpp

Research direction

Start at the la::MatrixCSR definition and inspect its defaulted move constructor alongside _request, scatter_rev_begin(), and scatter_rev_end(). Check the surrounding member state and existing coverage, then establish whether the move should transfer or explicitly document the MPI_Request behavior; done means the decision is implemented and the moved-from state cannot create an unsafe request use.

Written by the indexing model from the issue text.

Description

la::MatrixCSR's move constructor is = default and carries a long-standing todo:

/// Move constructor
/// @todo Check handling of MPI_Request
MatrixCSR(MatrixCSR&& A) = default;

_request is live only between scatter_rev_begin(), which starts an
MPI_Ineighbor_alltoallv into it, and scatter_rev_end(), which calls MPI_Wait on
it. MPI_Request is a plain handle, so a defaulted move copies the value and leaves
it set in the moved-from matrix: both objects then name the same request.

As far as I can tell this is currently harmless:

  • a moved-from object must not be used, so nothing should call scatter_rev_end() on
    it, and
  • MatrixCSR declares no destructor, so nothing acts on the stale handle when the
    moved-from matrix goes out of scope.

The receive buffer also survives a move: _ghost_value_data_in's heap block transfers
to the target, so an in-flight write still lands in storage the target owns.

So this is a latent weakness rather than an active bug. What makes it worth recording
is that the correctness argument rests entirely on the moved-from convention rather
than on the class's own state, and the same shape is not always so forgiving.
io::XDMFFile has a defaulted move over a raw hid_t where the destructor does act
on the handle, and there a move produces a genuine double close — which terminates,
since io::hdf5::close_file throws and ~XDMFFile is implicitly noexcept. I am
addressing that case separately.

Making MatrixCSR airtight is conceptually one line:

_request(std::exchange(A._request, MPI_REQUEST_NULL))

but it means replacing = default with a hand-written move constructor spelling out
~14 members, which is presumably why the todo is still open. The trade-off is that
maintenance cost against removing the reliance on convention — worth a decision either
way, even if the decision is to keep = default and document it.


AI assistance: I used Claude Opus 5 via Claude Code to draft parts of this issue. I
reviewed, edited, and take responsibility for the final contribution.

Dominant language
C++
Stars
1.2k
Forks
265
Avg merge
1d 19h
Merged PRs (30d)
77

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from FEniCS/dolfinx

All issues in FEniCS/dolfinx

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.