Seg Faults due to G4ParticleHPElasticData

I have been trying the most recent Geant4 Versions on an Apple M4 chip. When I run the example

advanced/hadrontherapy

I get a Segmentation fault: 11.

Running on another Geant4 application in debugger mode, I traced this to @G4ParticleHPElasticData::GetCrossSection. The debugger specifically says: EXC_BAD_ACCESS (code=1, address=0x8).

Are other people seeing this? How do we fix this?

Areg

p.s. My system :backhand_index_pointing_down:

Geant4 Version: 11.2.2 and 11.3.2
Operating System: Mac OS X 15.4
Compiler/Version: clang 15.0.0
CMake Version: 4.0.0


After a day in the debugger, I was able to track this down to the following class: G4PhysicsVector (as defined in G4PhysicsVector.icc). There are two glaring bugs in this class:

  • It has two variables, edgeMin and edgeMax which define the energy before and after a step (if I undertand correctly). Here’s the definition, from G4PhysicsVector.hh:
  G4double edgeMin = 0.0;  // Energy of first point
  G4double edgeMax = 0.0;  // Energy of the last point

Both are set to zero (why?) and are not modified anywhere.

  • The second bug is a c++ vector named dataVector. Throughout the class there are multiple references to the dataVector’s elements. While the vector is instantiated in the header file as
    std::vector<G4double> dataVector; // crossection/energyloss
    nowhere in the code is it initiated. Meaning it’s an empty vector. Any access to it ought to result in an out of bound error and/or a seg fault. Which is exactly what is breaking things.

To be clear, G4PhysicsVector is called from the following line in G4ParticleHPElasticData.cc:

      aXsection = (*((*theCrossSections)(index))).GetValue(theEkin, outOfRange);

Areg

The G4PhysicsVector is a container, and also a base class for more complex and interesting containers. Data members in general do not get filled in the .hh file. They get populated by member functions which perform that function, and which are usually implemented in the .cc file.

You should find that both of those get set to actual values in the many subclasses of G4PhysicsVector. The initializers in the .hh file are just the values assigned when you call the default constructor. As a specific example, look at the PutValue() function in G4PhysicsFreeVector.hh.

Dear Michael, thanks for the clarification. That explains what I am seeing, but doesn’t explain the fact that the applications are throwing segfaults.

Perhaps I am not using the debugger correctly – when I step through, I end up in the following function in the .icc.

It also seems to me that I cannot turn off optimizations during the build by passing the -DCMAKE_BUILD_TYPE=Debug during cmake stage…

That should turn off all the optimizations. Did you use that flag both for your application build and for your G4 build? If you switched modes for the G4 installation, you need to do a make clean and make uninstall (I think) to be sure nothing from a past build was left behind.

It’s very hard to read the screenshot (text copy-paste would help). But I think what I’m seeing is that the “dataVector” data member is invalid, with an address of 0x0. Since that’s an actual object (of type G4PVDataVector, which is just a typedef to std::vector<G4double>), that suggests to me that it’s the G4PhysicsVector you’re trying to look at which was never created.

Try stepping down a frame to where the PhysicsVector itself is being referenced, and see why it doesn’t exist. Maybe you want to post (by copy-paste, not screenshot), the traceback from your debugger session?

Thanks for the prompt responses! After enabling verbose output, I found out that Geant4’s -DCMAKE_BUILD_TYPE=Debug merely sets -Og, not -O0. I had to pass additional flags at cmake stage (-DCMAKE_CXX_FLAGS_DEBUG="-O0 -g" -DCMAKE_C_FLAGS_DEBUG="-O0 -g") for a trully unoptimized build.

Sorry for the poor quality of the screenshot. I ran

>lldb -- ./hadrontherapy

here’s the end of the output, along with the backtrace. Thank you again for your help!

(lldb) target create "./hadrontherapy"
Current executable set to '/Users/aregjan/geant4/geant4-11.3.2-install/share/Geant4/examples/advanced/hadrontherapy/RUN/hadrontherapy' (arm64).
(lldb) run

[LOTS OF OUTPUT DELETED]

G4WT0 > Run 0 starts ...
G4WT3 > ### Run 0 starts on worker thread 3.
G4WT3 > HadrontherapyRBEAccumulable::Reset()
G4WT3 > HadrontherapyRBEAccumulable::Initialize(): 400 voxels.
G4WT3 > Run 0 starts ...
G4WT2 > --> Event 0 starts with initial seeds (86695069,72936749).
Process 58220 stopped
* thread #5, stop reason = EXC_BAD_ACCESS (code=1, address=0x8)
    frame #0: 0x0000000101bb2df4 libG4event.dylib`G4PhysicsVector::Value(this=0x0000600001ce1ba0, e=0.17032601123969471) const at G4PhysicsVector.icc:246:11
   243 	  } 
   244 	  else
   245 	  {
-> 246 	    res = dataVector[idxmax + 1];
   247 	  }
   248 	  return res;
   249 	}
Target 0: (hadrontherapy) stopped.
(lldb) dataVector
error: 'dataVector' is not a valid command.
(lldb) print dataVector
(std::vector<double>) size=0 {}
(lldb) bt
* thread #5, stop reason = EXC_BAD_ACCESS (code=1, address=0x8)
  * frame #0: 0x0000000101bb2df4 libG4event.dylib`G4PhysicsVector::Value(this=0x0000600001ce1ba0, e=0.17032601123969471) const at G4PhysicsVector.icc:246:11
    frame #1: 0x0000000106aa6dd8 libG4processes.dylib`G4NeutronHPCaptureData::GetCrossSection(this=0x0000600000abe280, aP=0x00000001048f7930, anE=0x00006000013798c0, aT=293.14999999999998) at G4NeutronHPCaptureData.cc:236:49
    frame #2: 0x0000000106aa69a4 libG4processes.dylib`G4NeutronHPCaptureData::GetIsoCrossSection(this=0x0000600000abe280, dp=0x00000001048f7930, (null)=6, (null)=12, (null)=0x0000600003181d40, element=0x00006000013798c0, material=0x00000001246f1f10) at G4NeutronHPCaptureData.cc:103:17
    frame #3: 0x000000010642fb20 libG4processes.dylib`G4CrossSectionDataStore::GetIsoCrossSection(this=0x0000600000abf000, dp=0x00000001048f7930, Z=6, A=12, iso=0x0000600003181d40, elm=0x00006000013798c0, mat=0x00000001246f1f10, idx=1) at G4CrossSectionDataStore.cc:139:30
    frame #4: 0x000000010642fa08 libG4processes.dylib`G4CrossSectionDataStore::GetCrossSection(this=0x0000600000abf000, dp=0x00000001048f7930, elm=0x00006000013798c0, mat=0x00000001246f1f10) at G4CrossSectionDataStore.cc:121:7
    frame #5: 0x000000010642f838 libG4processes.dylib`G4CrossSectionDataStore::ComputeCrossSection(this=0x0000600000abf000, dp=0x00000001048f7930, mat=0x00000001246f1f10) at G4CrossSectionDataStore.cc:84:26
    frame #6: 0x000000010647ca90 libG4processes.dylib`G4CrossSectionDataStore::GetCrossSection(this=0x0000600000abf000, dp=0x00000001048f7930, mat=0x00000001246f1f10) at G4CrossSectionDataStore.hh:155:5
    frame #7: 0x000000010647c7ec libG4processes.dylib`G4HadronicProcess::DefineXSandMFP(this=0x000000010b1fb000) at G4HadronicProcess.hh:374:31
    frame #8: 0x0000000106478604 libG4processes.dylib`G4HadronicProcess::UpdateCrossSectionAndMFP(this=0x000000010b1fb000, e=0.17028442121647913) at G4HadronicProcess.cc:919:5
    frame #9: 0x00000001064784dc libG4processes.dylib`G4HadronicProcess::PostStepGetPhysicalInteractionLength(this=0x000000010b1fb000, track=0x00000001048f7d98, previousStepSize=0, condition=0x00000001049681d8) at G4HadronicProcess.cc:288:3
    frame #10: 0x00000001009a6ebc libG4tracking.dylib`G4VProcess::PostStepGPIL(this=0x000000010b1fb000, track=0x00000001048f7d98, previousStepSize=0, condition=0x00000001049681d8) at G4VProcess.hh:488:7
    frame #11: 0x00000001009a5360 libG4tracking.dylib`G4SteppingManager::DefinePhysicalStepLength(this=0x0000000104968050) at G4SteppingManager.cc:466:38
    frame #12: 0x00000001009a4ba4 libG4tracking.dylib`G4SteppingManager::Stepping(this=0x0000000104968050) at G4SteppingManager.cc:187:5
    frame #13: 0x00000001009baa30 libG4tracking.dylib`G4TrackingManager::ProcessOneTrack(this=0x0000600003899440, apValueG4Track=0x00000001048f7d98) at G4TrackingManager.cc:127:26
    frame #14: 0x0000000101b7d2c0 libG4event.dylib`G4EventManager::DoProcessing(this=0x000060001d6bd0e0, anEvent=0x0000000103215240, trackVector=0x0000000000000000, IDhasAlreadySet=false) at G4EventManager.cc:216:23
    frame #15: 0x0000000101b7e94c libG4event.dylib`G4EventManager::ProcessOneEvent(this=0x000060001d6bd0e0, anEvent=0x0000000103215240) at G4EventManager.cc:458:3
    frame #16: 0x0000000102581088 libG4run.dylib`G4WorkerTaskRunManager::ProcessOneEvent(this=0x0000000104967d00, i_event=-1) at G4WorkerTaskRunManager.cc:203:19
    frame #17: 0x0000000102580fc4 libG4run.dylib`G4WorkerTaskRunManager::DoEventLoop(this=0x0000000104967d00, n_event=316, macroFile=0x0000000000000000, n_select=-1) at G4WorkerTaskRunManager.cc:188:5
    frame #18: 0x000000010258245c libG4run.dylib`G4WorkerTaskRunManager::DoWork(this=0x0000000104967d00) at G4WorkerTaskRunManager.cc:460:3
    frame #19: 0x0000000102556614 libG4run.dylib`G4TaskRunManagerKernel::ExecuteWorkerTask() at G4TaskRunManagerKernel.cc:254:8
    frame #20: 0x0000000102550ab4 libG4run.dylib`G4TaskRunManager::AddEventTask(int)::$_4::operator()(this=0x0000600002912fc0) const at G4TaskRunManager.cc:411:5
    frame #21: 0x00000001025509c0 libG4run.dylib`std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(this=0x0000600002912fa8)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'()::operator()() const at TaskGroup.hh:548:13
    frame #22: 0x000000010255095c libG4run.dylib`decltype(std::declval<G4TaskRunManager::AddEventTask(int)::$_4>()()) std::__1::__invoke[abi:ue170006]<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'()&>(__f=0x0000600002912fa8) at invoke.h:340:25
    frame #23: 0x000000010255074c libG4run.dylib`std::__1::__packaged_task_func<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'(), std::__1::allocator<std::__1::enable_if<std::is_void<void>::value, void>::type PTL::TaskGroup<void, void, 0l>::exec<G4TaskRunManager::AddEventTask(int)::$_4, void>(G4TaskRunManager::AddEventTask(int)::$_4)::'lambda'()>, void ()>::operator()(this=0x0000600002912fa0) at future:1706:12
    frame #24: 0x0000000102533c68 libG4run.dylib`std::__1::__packaged_task_function<void ()>::operator()(this=0x0000600000af7750) const at future:1892:12
    frame #25: 0x0000000102533a60 libG4run.dylib`std::__1::packaged_task<void ()>::operator()(this=0x0000600000af7750) at future:2094:9
    frame #26: 0x00000001025339ec libG4run.dylib`decltype(std::forward<std::__1::packaged_task<void ()>>(fp)()) PTL::impl::apply<std::__1::packaged_task<void ()>, std::__1::tuple<>>(_func=0x0000600000af7750, _args=size=0, (null)=PTL::impl::index_sequence<> @ 0x000000017002abce) at CxxBackports.hh:122:12
    frame #27: 0x00000001025339c0 libG4run.dylib`void PTL::apply<std::__1::packaged_task<void ()>, std::__1::tuple<>>(_func=0x0000600000af7750, _args=size=0) at CxxBackports.hh:137:5
    frame #28: 0x0000000102530de8 libG4run.dylib`PTL::Task<void>::operator()(this=0x0000600000af7718) at Task.hh:168:13
    frame #29: 0x0000000102fbbed0 libG4ptl.3.dylib`PTL::ThreadPool::execute_thread(this=0x00000001246f1800, _task_queue=0x0000600000f7a060) at ThreadPool.cc:821:17
    frame #30: 0x0000000102fbb2ac libG4ptl.3.dylib`PTL::ThreadPool::start_thread(tp=0x00000001246f1800, _data=0x00000001246f1928 size=4, _idx=4) at ThreadPool.cc:102:9
    frame #31: 0x0000000102fd0860 libG4ptl.3.dylib`decltype(std::declval<void (*)(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long)>()(std::declval<PTL::ThreadPool*>(), std::declval<std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*>(), std::declval<unsigned long>())) std::__1::__invoke[abi:ue170006]<void (*)(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long), PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, unsigned long>(__f=0x0000600002ab6768, __args=0x0000600002ab6770, __args=size=1, __args=0x0000600002ab6780) at invoke.h:340:25
    frame #32: 0x0000000102fd07d4 libG4ptl.3.dylib`void std::__1::__thread_execute[abi:ue170006]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long), PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, unsigned long, 2ul, 3ul, 4ul>(__t=size=5, (null)=__tuple_indices<2UL, 3UL, 4UL> @ 0x000000017002af7f) at thread.h:227:5
    frame #33: 0x0000000102fd002c libG4ptl.3.dylib`void* std::__1::__thread_proxy[abi:ue170006]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)(PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, long), PTL::ThreadPool*, std::__1::vector<std::__1::shared_ptr<PTL::ThreadData>, std::__1::allocator<std::__1::shared_ptr<PTL::ThreadData>>>*, unsigned long>>(__vp=0x0000600002ab6760) at thread.h:238:5
    frame #34: 0x00000001875cdc0c libsystem_pthread.dylib`_pthread_start + 136
(lldb) print dataVector
(std::vector<double>) size=0 {}
(lldb) exit

That helps! I can at least see the problem: The specific G4PhysicsVector that NeutronHPCapture wants to use is not being filled during /run/initialize.

Something that I ran into a very long time ago (and which I don’t know whether has been fixed or not), is that NeutronHP needs you to pre-create all of your materials even before your geometry gets built!

In our simulaion framework, we defined a “MaterialsManager” which we instantiate in main(). That MaterialsManager in turn defines all of our materials in its constructor. I find this really annoying – it makes it harder to add components made of new materials, etc. – but if we don’t do that, NeutronHP eventually crashes.

Fascinating. This problem started happening after I switched from an intel Mac to an M4 Mac. And yes, this is happening only when I have NeutronHP-relevant processes.

Can you suggest a Geant4 example involving NeutronHP where the MaterialsManager is used correctly in main()?

Much thanks.

Areg

I tried a few other things. I took example B3a (from “basic”), added the following into the physics list:

RegisterPhysics( new G4HadronPhysicsQGSP_BIC_HP());
RegisterPhysics( new G4HadronElasticPhysicsHP());

set the particle to a neutron, and bam – segfault! Using G4HadronElasticPhysics() seems to work fine.

I think this is a real bug, and a very serious one. @makotoasai , any thoughts on workarounds? Currently we basically cannot use HP libraries with neutrons or protons…

Areg

I found out the source of the problem.

Turns out that this whole time my G4NEUTRONHPDATA env variable was pointing to the entirely wrong location. Once I set it correctly everything worked fine.

This is still a serious bug. The HP Physics classes should not seg fault when the input file is not found: they should instead return a “file not open” error of sorts, ideally with the file path. As is a standard practice in all software design. That way people do not spend ~days chasing non-existent problems.

Areg