Skip to content

Child class of colvarproxy with custom close_output_stream cannot be safely deleted #930

Description

@HanatoK

Describe the bug
When using NAMD with the CUDAGM plugin, if I try to remove the Colvars proxy by

gpuGlobalCreateClient libcudaglobalmastercolvars.so COLVARS rmsd_gpu.colvars
run 500
gpuGlobalRemoveClient COLVARS

then NAMD would crash. Backtrace shows:

#0  std::__basic_file<char>::is_open (this=this@entry=0x70) at basic_file.cc:304
#1  0x00007ffff7736f30 in std::basic_filebuf<char, std::char_traits<char> >::is_open (this=0x8)
    at /usr/src/debug/gcc-16.0.1+git8711/obj-x86_64-suse-linux/x86_64-suse-linux/libstdc++-v3/include/fstream:279
#2  std::basic_filebuf<char, std::char_traits<char> >::close (this=0x8) at /usr/src/debug/gcc-16.0.1+git8711/obj-x86_64-suse-linux/x86_64-suse-linux/libstdc++-v3/include/bits/fstream.tcc:256
#3  0x00007ffdcd32a05d in std::basic_ofstream<char, std::char_traits<char> >::close (this=0x0) at /usr/bin/../lib64/gcc/x86_64-suse-linux/16/../../../../include/c++/16/fstream:1053
#4  colvarproxy_io::close_output_streams (this=0x7ffdb06b58f8) at /home/hanatok/HDD/Documents/git/colvars/src/colvarproxy_io.cpp:500
#5  0x00007ffdcd31b8eb in colvarproxy::~colvarproxy (this=0x7ffdb06b55a0) at /home/hanatok/HDD/Documents/git/colvars/src/colvarproxy.cpp:468
#6  0x00007ffdcd0cd699 in colvarproxy_impl::~colvarproxy_impl (this=0x70) at /home/hanatok/HDD/Documents/git/colvars/namd/cudaglobalmaster/colvarproxy_cudaglobalmaster.C:275
#7  0x00007ffdcd0d2ba4 in std::default_delete<colvarproxy_impl>::operator() (this=0x7ffff19c1e80, __ptr=0x70)
    at /usr/bin/../lib64/gcc/x86_64-suse-linux/16/../../../../include/c++/16/bits/unique_ptr.h:92
#8  std::unique_ptr<colvarproxy_impl, std::default_delete<colvarproxy_impl> >::~unique_ptr (this=0x7ffff19c1e80)
    at /usr/bin/../lib64/gcc/x86_64-suse-linux/16/../../../../include/c++/16/bits/unique_ptr.h:398
#9  CudaGlobalMasterColvars::~CudaGlobalMasterColvars (this=0x7ffff19c1e20) at /home/hanatok/HDD/Documents/git/colvars/namd/cudaglobalmaster/colvarproxy_cudaglobalmaster.C:1053
#10 0x00007ffdcd0d2bc9 in CudaGlobalMasterColvars::~CudaGlobalMasterColvars (this=0x70) at /home/hanatok/HDD/Documents/git/colvars/namd/cudaglobalmaster/colvarproxy_cudaglobalmaster.C:1053
#11 0x0000000000c02d1e in dlloader::DLLoader<CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient>::DLGetInstance()::{lambda(CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient*)#1}::operator()(CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient*) const (__closure=<optimized out>, p=<optimized out>) at src/dlloader.h:117
#12 std::_Sp_counted_deleter<CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient*, dlloader::DLLoader<CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient>::DLGetInstance()::{lambda(CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient*)#1}, std::allocator<void>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (this=<optimized out>) at /usr/include/c++/15/bits/shared_ptr_base.h:526
#13 0x0000000000b8216a in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use (this=0x7ffdb06b5cf0) at /usr/include/c++/15/bits/shared_ptr_base.h:174
#14 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use_cold (this=0x7ffdb06b5cf0) at /usr/include/c++/15/bits/shared_ptr_base.h:198
#15 0x0000000000bfaaf3 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x7ffff71fa588) at /usr/include/c++/15/bits/shared_ptr_base.h:1069
#16 std::__shared_ptr<CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x7ffff71fa580) at /usr/include/c++/15/bits/shared_ptr_base.h:1531
#17 std::shared_ptr<CudaGlobalMaster::CUDAGM_NS::CudaGlobalMasterClient>::~shared_ptr (this=0x7ffff71fa580) at /usr/include/c++/15/bits/shared_ptr.h:175
#18 ComputeMgr::recvCudaGlobalMasterRemoveMsg (this=this@entry=0x7ffff004e1e0, args=std::vector of length 1, capacity 1 = {...}) at src/ComputeMgr.C:1677
#19 0x0000000000bfd22f in CkIndex_ComputeMgr::_call_recvCudaGlobalMasterRemoveMsg_marshall20 (impl_msg=<optimized out>, impl_obj_void=0x7ffff004e1e0) at inc/ComputeMgr.def.h:2299
#20 0x00000000018c4e7d in CkDeliverMessageFree ()
#21 0x00000000018ca59b in _processHandler(void*, CkCoreState*) ()
#22 0x000000000198a0ea in CsdScheduleForever ()
#23 0x000000000198a6b5 in CsdScheduler ()
#24 0x00000000019dcd7e in ConverseRunPE(int) ()
#25 0x00000000019dcfa4 in call_startfn(void*) ()
#26 0x00007ffff729bd51 in start_thread (arg=<optimized out>) at pthread_create.c:448
#27 0x00007ffff7320bcc in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

After investigation, I have found that colvarproxy_io::close_output_streams shouldn't be called, as it has already overwritten by colvarproxy_impl::close_output_streams. However, since colvarproxy_impl is the child class of colvarproxy, it gets destroyed at first, and then in the deconstructor of the parent class (colvarproxy::~colvarproxy), the original colvarproxy_io::close_output_streams is called because the child class has been deconstructed.

Back-end (i.e. package that uses Colvars)
NAMD + CUDAGM.

Colvars version
Paste the part of Colvars standard output starting with:

colvars: Initializing the collective variables module, version 2026-03-24.

Expected behavior
Any child classes of colvarproxy with close_output_streams overwritten should be safely destroyed.

Output log

Info: CudaGlobalMasterServer: removing client "COLVARS"
Info: CudaGlobalMasterClient "COLVARS" removed
[1]    8365 segmentation fault (core dumped)   +p2 ./rmsd_cudagm_reload.namd

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugTo be used only in issues

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions