Skip to content

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

@HanatoK

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions