Segmentation fault When trying to save results of more than one event

_Geant4 Version:_v11.3.0
_Operating System:_macOS Sequoia 15.2
_Compiler/Version:_v16.0.0
_CMake Version:_v3.31.2


Hello! I’m using Geant4 to model the particle production from a 120 GeV beam of protons incident on a beam dump made of iron. I’ve recently made some changes to my code, trying to record the particle name, kinetic energy, and momentum right as it hits the detector volume using ntuples to write to a .csv file, instead of recording the data each step through the detector. The code works for just one event, however, when I try to generate more than one event using “/run/beamOn #” or to generate a second event after the first using the both the green play button on the visualizer and “/run/beamOn 1”, my program crashes with a segmentation fault.

The strange thing is that when the segmentation fault occurs, it seems to occur after the beginning of the event generation as the initial proton data will be saved to the .csv file but never any other generated particles.

Here’s an example of the output with just one event, where the segmentation fault does not occur:

Particle Name, 4-mom.: proton, (119998.0548431, -1.5579852408857, 3448.6744494557, 120883.50359411)
Particle Name, 4-mom.: neutron, (0.0030342622349053, -1.3995103565934, 1.9054887945835, -0.33506387510176)

And here’s the output when I try to generate 2 events:

Particle Name, 4-mom.: proton, (119998.0548431, -1.5579852408857, 3448.6744494557, 120883.50359411)
Particle Name, 4-mom.: neutron, (0.0030342622349053, -1.3995103565934, 1.9054887945835, -0.33506387510176)

Particle Name, 4-mom.: proton, (119998.33490934, -1.1788201029167, 3379.7007084187, 120885.73183486)
zsh: segmentation fault ./simDarkQuest

I’ve attached my new code, where I save the particle data, below. Any advice or suggestions anyone has on how to fix this issue would be greatly appreciated!

#include "detector.hh"
#include "G4ParticleDefinition.hh"
#include "G4AnalysisManager.hh"

MySensitiveDetector::MySensitiveDetector(G4String name) : G4VSensitiveDetector(name)
{}

MySensitiveDetector::~MySensitiveDetector()
{}

G4bool MySensitiveDetector::ProcessHits(G4Step *aStep, G4TouchableHistory *ROHist)
{
    G4Track *track = aStep->GetTrack();
    
    G4LogicalVolume* post_volume = aStep->GetPostStepPoint()->GetTouchableHandle()->GetVolume()->GetLogicalVolume();
    G4String vol_name = post_volume->GetName();
    G4bool boundary = aStep->GetPreStepPoint()->GetStepStatus()==fGeomBoundary;

    if ((vol_name == "Detector") && (boundary)){
        //get kinetic energy, momenta, particle name
        G4double KE = aStep->GetPostStepPoint()->GetKineticEnergy();
        G4double p_x = aStep->GetPostStepPoint()->GetMomentum().x(); 
        G4double p_y = aStep->GetPostStepPoint()->GetMomentum().y();
        G4double p_z = aStep->GetPostStepPoint()->GetMomentum().z();
        
        G4String particleName = aStep->GetTrack()->GetDynamicParticle()->GetDefinition()->GetParticleName();
        
        //print out the 4-mom.
        G4cout << "Particle Name, 4-mom.: " << particleName << ", " << "(" << KE << ", " << p_x << ", " << p_y << ", " << p_z << ")" << G4endl;

        //record the 4-mom.
        G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();
        analysisManager->FillNtupleSColumn(0, 0, particleName);
        analysisManager->FillNtupleDColumn(0, 1, KE);
        analysisManager->FillNtupleDColumn(0, 2, p_x); 
        analysisManager->FillNtupleDColumn(0, 3, p_y);
        analysisManager->FillNtupleDColumn(0, 4, p_z);
        analysisManager->AddNtupleRow(0);
     }

     return 1;

}

Hello,

It’s worthwhile to learn how to use your compiler’s debugging tools to tell you exactly where the segfault occurs instead of relying on print outs and a vague understanding of when things happen. In your case I would recommend trying LLDB if this was compiled using LLVM, if you or someone else reading this is using GCC try GDB.

There isn’t anything obvious to me in your code that would cause the segfault, but based on what you describe I’d guess that you’re closing your Ntuple in the EndOfEventAction instead of the EndOfRunAction, and so during the second even your code is trying to access something that does not exist. Or you’re closing it somewhere between events at any rate. Make sure all file creation, writing and deletion is in the RunAction only.

Hi–thank you so much for the advice! I don’t have an EventAction file created for this project, as the earlier code I created didn’t require one. I fill the Ntuple lines in my detector code I posted above, and then create, write, and close the file in my RunAction file. I’ve attached that code below.

Do you think that my not having an EventAction file could be causing some issue and hence generating the segfault? Any further advice you have would be greatly appreciated!

#include "run.hh"

MyRunAction::MyRunAction()
{}

MyRunAction::~MyRunAction()
{}

void MyRunAction::BeginOfRunAction(const G4Run*)
{
    G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();

    analysisManager->OpenFile("output.csv");
    analysisManager->CreateNtuple("step", "step");
    analysisManager->CreateNtupleSColumn("Particle Name");
    analysisManager->CreateNtupleDColumn("Particle Energy");
    analysisManager->CreateNtupleDColumn("Particle p_x"); 
    analysisManager->CreateNtupleDColumn("Particle p_y");
    analysisManager->CreateNtupleDColumn("Particle p_z");
    analysisManager->FinishNtuple();


}

void MyRunAction::EndOfRunAction(const G4Run*)
{
    G4AnalysisManager* analysisManager = G4AnalysisManager::Instance();

    analysisManager->Write();
    analysisManager->CloseFile();
}

Not having an EventAction class shouldn’t cause a segfault by itself, so long as somewhere else in the program isn’t trying to access one.

I suggest trying the debugger I mentioned, because where the segfault is actually occurring and what is making it happen isn’t clear from the code you’ve shared. If you can’t run the debugger, can you try sharing the entire code through GitHub or something similar?

Also, are you running this in multi-threaded mode? If you are try single-threaded.

Thank you so much, once again! I’ve gotten LLDB working on my computer and ran my program through it. Here’s what it output when the segfault occurred:

Process 24491 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10)
    frame #0: 0x000000010001572c simDarkQuest`G4VPhysicalVolume::GetLogicalVolume(this=0x0000000000000000) const at G4VPhysicalVolume.icc:45:10
   42  	inline
   43  	G4LogicalVolume* G4VPhysicalVolume::GetLogicalVolume() const
   44  	{
-> 45  	  return flogical;
   46  	}
   47  	
   48  	inline
Target 0: (simDarkQuest) stopped.

Here’s a list of the function calls that led up to that point:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10)
  * frame #0: 0x000000010001572c simDarkQuest`G4VPhysicalVolume::GetLogicalVolume(this=0x0000000000000000) const at G4VPhysicalVolume.icc:45:10
    frame #1: 0x0000000100015288 simDarkQuest`MySensitiveDetector::ProcessHits(this=0x0000600002490750, aStep=0x0000600003294b40, ROHist=0x0000000000000000) at detector.cc:53:98
    frame #2: 0x00000001009c9d08 libG4tracking.dylib`G4SteppingManager::Stepping() + 804
    frame #3: 0x00000001009dc7f4 libG4tracking.dylib`G4TrackingManager::ProcessOneTrack(G4Track*) + 872
    frame #4: 0x0000000100932b60 libG4event.dylib`G4EventManager::DoProcessing(G4Event*, std::__1::vector<G4Track*, std::__1::allocator<G4Track*>>*, bool) + 2244
    frame #5: 0x0000000100bb6c1c libG4run.dylib`G4RunManager::ProcessOneEvent(int) + 48
    frame #6: 0x0000000100bb6aec libG4run.dylib`G4RunManager::DoEventLoop(int, char const*, int) + 68
    frame #7: 0x0000000100bb5fbc libG4run.dylib`G4RunManager::BeamOn(int, char const*, int) + 128
    frame #8: 0x0000000100bd2fc8 libG4run.dylib`G4RunMessenger::SetNewValue(G4UIcommand*, G4String) + 988
    frame #9: 0x0000000100df7418 libG4intercoms.dylib`G4UIcommand::DoIt(G4String const&) + 2344
    frame #10: 0x0000000100e0e96c libG4intercoms.dylib`G4UImanager::ApplyCommand(char const*) + 3624
    frame #11: 0x000000010035d474 libG4interfaces.dylib`G4VBasicShell::ExecuteCommand(G4String const&) + 64
    frame #12: 0x000000010035e0b8 libG4interfaces.dylib`G4VBasicShell::ApplyShellCommand(G4String const&, bool&, bool&) + 2588
    frame #13: 0x000000010036b260 libG4interfaces.dylib`G4UIQt::CommandEnteredCallback() + 1244
    frame #14: 0x00000001021ed004 QtCore`___lldb_unnamed_symbol16562 + 964
    frame #15: 0x00000001021ed004 QtCore`___lldb_unnamed_symbol16562 + 964
    frame #16: 0x00000001019b3a44 QtWidgets`QWidgetLineControl::processKeyEvent(QKeyEvent*) + 396
    frame #17: 0x00000001019ad7d0 QtWidgets`QLineEdit::keyPressEvent(QKeyEvent*) + 28
    frame #18: 0x000000010190bc40 QtWidgets`QWidget::event(QEvent*) + 1436
    frame #19: 0x00000001019ad1c8 QtWidgets`QLineEdit::event(QEvent*) + 416
    frame #20: 0x00000001018e51a0 QtWidgets`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 236
    frame #21: 0x00000001018e6258 QtWidgets`QApplication::notify(QObject*, QEvent*) + 1144
    frame #22: 0x00000001021d0210 QtCore`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 180
    frame #23: 0x000000010191e37c QtWidgets`___lldb_unnamed_symbol13557 + 380
    frame #24: 0x00000001018e51a0 QtWidgets`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 236
    frame #25: 0x00000001018e5ff0 QtWidgets`QApplication::notify(QObject*, QEvent*) + 528
    frame #26: 0x00000001021d0210 QtCore`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 180
    frame #27: 0x0000000101d335b8 QtGui`QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyEvent*) + 148
    frame #28: 0x0000000101d23d90 QtGui`QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 112
    frame #29: 0x0000000101d21820 QtGui`QWindowSystemInterface::flushWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 308
    frame #30: 0x0000000105229ef0 libqcocoa.dylib`___lldb_unnamed_symbol3077 + 964
    frame #31: 0x000000010522a074 libqcocoa.dylib`___lldb_unnamed_symbol3078 + 92
    frame #32: 0x000000019a343e5c AppKit`-[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 316
    frame #33: 0x000000019a343b50 AppKit`-[NSWindow(NSEventRouting) sendEvent:] + 284
    frame #34: 0x000000010522d644 libqcocoa.dylib`___lldb_unnamed_symbol3357 + 280
    frame #35: 0x000000019ab80378 AppKit`-[NSApplication(NSEventRouting) sendEvent:] + 2360
    frame #36: 0x0000000105232730 libqcocoa.dylib`___lldb_unnamed_symbol3645 + 56
    frame #37: 0x000000019a7874e8 AppKit`-[NSApplication _handleEvent:] + 60
    frame #38: 0x000000019a210088 AppKit`-[NSApplication run] + 520
    frame #39: 0x000000010522fc58 libqcocoa.dylib`___lldb_unnamed_symbol3507 + 980
    frame #40: 0x00000001021cdf74 QtCore`QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 328
    frame #41: 0x00000001021d0708 QtCore`QCoreApplication::exec() + 124
    frame #42: 0x000000010037947c libG4interfaces.dylib`G4UIQt::SessionStart() + 232
    frame #43: 0x000000010000b360 simDarkQuest`main(argc=1, argv=0x000000016fdff6a8) at simDarkQuest.cc:63:9
    frame #44: 0x000000019624c274 dyld`start + 2840

I could be wrong, but it looks as though the logical volume is a null pointer and that’s why the segfault is occurring, though I’m not entirely sure why that would be or how to fix it. Do you think that is accurate and do you have any suggestions?

Almost, but not quite!

Your physical volume is a null pointer. When you dereference that to ask for the LV, that’s your segfault. So why is the PV a null pointer? Without even looking at your code, I’ll be that you’re doing this in your SD:

  1. postPoint = step->GetPostStepPoint();
  2. postPV = postPoint->GetVolume();
  3. postLV = postPV->GetLogicalVolume();
    KABOOM

If you dial back before 2. above, and look at postPoint->GetStepStatus(), you’ll discover that it’s fWorldBoundary. When the track leaves the World, there’s no post-step volume, so the PV is null.

Check for the null pointer before dereferencing, or in this case, check the step status.

That was exactly what was going wrong–thank you so much! I made sure to check the step status first and the segfault no longer occurs.