Я пытаюсь сделать несколько соединений ssh (используя libssh 0.7.5) и распараллеливать их, используя boost :: threads.
После распараллеливания я заметил, что из 20 выполнений моего исполняемого файла 3 произошел сбой с ошибкой glibc «двойное освобождение или повреждение», а 2 — с ошибкой сегментации.
Эти ошибки не наблюдались при попытке выполнить последовательные вызовы ssh-соединения.
Используя gdb в качестве инструмента отладки, я обнаружил, что приведенная ниже обратная трассировка вызывает проблемы:
#0 0x00007ffff49735e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1 0x00007ffff4974dc5 in abort () at abort.c:92
#2 0x00007ffff49b14f7 in __libc_message (do_abort=2, fmt=0x7ffff4a99a60 "*** glibc detected *** %s: %s: 0x%s ***\n")
at ../sysdeps/unix/sysv/linux/libc_fatal.c:198
#3 0x00007ffff49b6f3e in malloc_printerr (action=3, str=0x7ffff4a99df0 "double free or corruption (!prev)",
ptr=<value optimized out>, ar_ptr=<value optimized out>) at malloc.c:6360
#4 0x00007ffff49b9dd0 in _int_free (av=0x7fffe0000020, p=0x7fffe0001810, have_lock=1) at malloc.c:4846
#5 0x00007ffff49bcd60 in _int_realloc (av=0x7fffe0000020, oldp=0x7fffe0001810, oldsize=<value optimized out>, nb=272)
at malloc.c:5398
#6 0x00007ffff49bd058 in __libc_realloc (oldmem=0x7fffe0001820, bytes=256) at malloc.c:3833
#7 0x00007ffff6f06ccf in CRYPTO_realloc () from /usr/lib64/libcrypto.so.10
#8 0x00007ffff6f822be in lh_insert () from /usr/lib64/libcrypto.so.10
#9 0x00007ffff6f09d9b in OBJ_NAME_add () from /usr/lib64/libcrypto.so.10
#10 0x00007ffff6f914e7 in OpenSSL_add_all_ciphers () from /usr/lib64/libcrypto.so.10
#11 0x00007ffff6f911ae in OPENSSL_add_all_algorithms_noconf () from /usr/lib64/libcrypto.so.10
#12 0x00007ffff7b69c8a in ssh_crypto_init () from /home/utils/libssh-0.7.5/lib/libssh.so.4
#13 0x00007ffff7b6ae05 in ssh_init () from /home/utils/libssh-0.7.5/lib/libssh.so.4
#14 0x00007ffff7b65799 in ssh_connect () from /home/utils/libssh-0.7.5/lib/libssh.so.4
#15 0x000000000043f766 in SSHConnector::SSHConnector(std::basic_string<char, std::char_traits<char>, std::allocator<char> >) () at SSHConnector.cpp:44
#16 0x0000000000433855 in connect_host(connect_host_report*) () at Util.cpp:339
#17 0x000000000043f57d in void boost::_bi::list1<boost::_bi::value<connect_host_report*> >::operator()<void (*)(connect_host_report*), boost::_bi::list0>(boost::_bi::type<void>, void (*&)(connect_host_report*), boost::_bi::list0&, int)
() at /home/utils/boost-1.55.0//include/boost/bind/bind.hpp:253
#18 0x000000000043f0f9 in boost::_bi::bind_t<void, void (*)(connect_host_report*), boost::_bi::list1<boost::_bi::value<connect_host_report*> > >::operator()() () at /home/utils/boost-1.55.0//include/boost/bind/bind_template.hpp:20
#19 0x000000000043e738 in boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(connect_host_report*), boost::_bi::list1<boost::_bi::value<connect_host_report*> > > >::run() ()
at /home/utils/boost-1.55.0//include/boost/thread/detail/thread.hpp:117
#20 0x00007ffff60995da in thread_proxy () from /home/utils/boost-1.55.0//lib/libboost_thread.so.1.55.0
#21 0x00007ffff6c86aa1 in start_thread (arg=0x7ffff1593700) at pthread_create.c:301
#22 0x00007ffff4a29aad in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:115
Также вставляем соответствующий код из SSHConnector (строка 44 ssh_connect является источником ошибкир)
28 string error_info;29
30 ssh_session_object = ssh_new();
31 if (ssh_session_object == NULL) {
32 error_info = "Could not create SSH session";
33 throw ConnectionUnsuccessfulException(hostname, error_info,
34 CLEANUP_NOT_REQUIRED);
35 }
36
37 ssh_options_set(ssh_session_object, SSH_OPTIONS_HOST, hostname.c_str());
38 ssh_options_set(ssh_session_object, SSH_OPTIONS_LOG_VERBOSITY,
39 &verbosity);
40 ssh_options_set(ssh_session_object, SSH_OPTIONS_TIMEOUT,
41 &ssh_connection_timeout);
42
43 int rc;
44 rc = ssh_connect(ssh_session_object);
Также попробовал тест с valgrind:
==641==
==641== HEAP SUMMARY:
==641== in use at exit: 16,104 bytes in 540 blocks
==641== total heap usage: 4,791 allocs, 4,251 frees, 559,189 bytes allocated
==641==
==641== Searching for pointers to 540 not-freed blocks
==641== Checked 1,006,816 bytes
==641==
==641== LEAK SUMMARY:
==641== definitely lost: 0 bytes in 0 blocks
==641== indirectly lost: 0 bytes in 0 blocks
==641== possibly lost: 0 bytes in 0 blocks
==641== still reachable: 16,104 bytes in 540 blocks
==641== suppressed: 0 bytes in 0 blocks
==641== Rerun with --leak-check=full to see details of leaked memory
==641==
==641== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
--641--
--641-- used_suppression: 4 U1004-ARM-_dl_relocate_object
--641-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a
==641==
==641== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
Кто-нибудь может подсказать, что может быть причиной случайного поведения этой ошибки?
Версии OpenSSL до 1.1 не являются поточно-ориентированными, если только приложение не регистрирует свои собственные обратные вызовы блокировки. libssh
предоставляет набор блокирующих обратных вызовов по умолчанию, но его последовательность инициализации сама по себе не является поточно-ориентированной (в версии 0.7), поэтому вам нужно вызвать ssh_init
или же ssh_threads_init
явно, чтобы избежать условий гонки.
Других решений пока нет …