Skip to content

observables: reject nonexistent particle ids (bug-sweep #23) - #5357

Draft
RudolfWeeber wants to merge 1 commit into
espressomd:pythonfrom
RudolfWeeber:fix/bug-23-pidobservable-oob
Draft

observables: reject nonexistent particle ids (bug-sweep #23)#5357
RudolfWeeber wants to merge 1 commit into
espressomd:pythonfrom
RudolfWeeber:fix/bug-23-pidobservable-oob

Conversation

@RudolfWeeber

Copy link
Copy Markdown
Contributor

The documented "(existing) particle" precondition for observable ids was
enforced by no layer (Python, script interface, or core). Passing a
nonexistent id to a get_all_particle_positions-family chain observable
(ParticleDistances, BondAngles, BondDihedrals, CosPersistenceAngles, RDF)
made fetch_particles silently drop the missing id, so detail::get_argsort
produced an out-of-range index that detail::get_all_particle_positions
consumed as an out-of-bounds vector read (assert-abort in debug builds,
heap garbage or SIGSEGV in release). The Map family (ParticlePositions/
Velocities/Forces) returned silently-wrong values via the same dropped id.

Add a collective existence check at the single chokepoint
PidObservable::operator(), which runs before fetch_particles() for every
particle-based observable. It counts locally-present, non-ghost particles
matching the requested ids, all_reduce()s the count across ranks, and if it
does not equal ids().size() throws std::runtime_error naming the first
missing id. The reductions are collective on every rank, so there is no MPI
deadlock, and the exception is surfaced to Python via the script interface's
parallel_try_catch wrapper. This mirrors the existing precedent in
script_interface/analysis/Analysis.cpp::check_topology.

Extend testsuite/python/observable_chain.py with a multi-rank in-process
test asserting RuntimeError for a nonexistent id, and a single-rank
subprocess crash-safety test that treats an abort/segfault as failure.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

🤖 Generated with Claude Code

The documented "(existing) particle" precondition for observable ids was
enforced by no layer (Python, script interface, or core). Passing a
nonexistent id to a get_all_particle_positions-family chain observable
(ParticleDistances, BondAngles, BondDihedrals, CosPersistenceAngles, RDF)
made fetch_particles silently drop the missing id, so detail::get_argsort
produced an out-of-range index that detail::get_all_particle_positions
consumed as an out-of-bounds vector read (assert-abort in debug builds,
heap garbage or SIGSEGV in release). The Map family (ParticlePositions/
Velocities/Forces) returned silently-wrong values via the same dropped id.

Add a collective existence check at the single chokepoint
PidObservable::operator(), which runs before fetch_particles() for every
particle-based observable. It counts locally-present, non-ghost particles
matching the requested ids, all_reduce()s the count across ranks, and if it
does not equal ids().size() throws std::runtime_error naming the first
missing id. The reductions are collective on every rank, so there is no MPI
deadlock, and the exception is surfaced to Python via the script interface's
parallel_try_catch wrapper. This mirrors the existing precedent in
script_interface/analysis/Analysis.cpp::check_topology.

Extend testsuite/python/observable_chain.py with a multi-rank in-process
test asserting RuntimeError for a nonexistent id, and a single-rank
subprocess crash-safety test that treats an abort/segfault as failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@RudolfWeeber RudolfWeeber added this to the ESPResSo 5.0.2 milestone Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant