Fix Surface Flux Tally Seg Fault#3891
Conversation
PR openmc-dev#3742 moved the surface dereference in event_cross_surface() above the lattice translation check so that the surf variable would be available for score_surface_tally() at the end of the function. This caused an out-of-bounds access on model::surfaces when the particle crosses a lattice boundary, because surface() is SURFACE_NONE (0) and surface_index() evaluates to -1. The fix moves the surface dereference and score_surface_tally call into the else branch (actual surface crossings), where surface() is guaranteed to be a valid nonzero surface ID. A regression test with a lattice geometry and surface tallies is added to prevent recurrence. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Thanks for digging into this issue @jtramm. I do not think it makes sense to not score anything when crossing lattice boundaries. |
|
@GuySten - that makes sense, I hadn't thought of the cellfrom filter issue. Claude is also saying " In score_surface_tally(): surf.normal() is a virtual method call. For lattice crossings there is no surface, so this either crashes (if the caller passed garbage) or computes a garbage normal." Anyhow - I will mark this as draft if you want to put in your own PR with a more robust fix. |
|
I think I will have time to fix this next week. |
|
Thanks @GuySten! I'll also note that the bug is not only triggered when the Flux Tally is in use. It gets triggered potentially anytime there is a lattice due to the: const auto& surf {*model::surfaces[surface_index()].get()};being moved up before the conditional by #3742. So, from what I'm seeing, it's a fairly critical bug that may affect most people (given how common lattices are), not just those using the new tally. |
|
That does not makes sense to me. We have a regression test suite that does contain lattices. I think the bug should only appear when using both surface tallies and lattices together in the same problem. |
void Particle::event_cross_surface()
{
// Saving previous cell data
for (int j = 0; j < n_coord(); ++j) {
cell_last(j) = coord(j).cell();
}
n_coord_last() = n_coord();
// Set surface that particle is on and adjust coordinate levels
surface() = boundary().surface();
n_coord() = boundary().coord_level();
const auto& surf {*model::surfaces[surface_index()].get()};My reading is that if a lattice is present this function will trigger but I discovered the bug originally with a model that didn't have any tallies in it at all, just a lattice. |
|
When I ran your example the code crash for me after this line, in the score_surface_tally function. Maybe undefined behavior causes it to crash randomly in different places. |
Description
PR #3742 moved the surface dereference in event_cross_surface() above the lattice translation check so that the surf variable would be available for score_surface_tally() at the end of the function. This caused an out-of-bounds access on model::surfaces when the particle crosses a lattice boundary, because surface() is SURFACE_NONE (0) and surface_index() evaluates to -1.
The fix moves the surface dereference and score_surface_tally call into the else branch (actual surface crossings), where surface() is guaranteed to be a valid nonzero surface ID. A regression test with a lattice geometry and surface tallies is added to prevent recurrence.
Please include a summary of the change and which issue is fixed if applicable. Please also include relevant motivation and context.
Fixes #3890
Checklist