Hello community, here is the log from the commit of package socket_wrapper for openSUSE:Factory checked in at 2017-12-05 01:30:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/socket_wrapper (Old) and /work/SRC/openSUSE:Factory/.socket_wrapper.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "socket_wrapper" Tue Dec 5 01:30:25 2017 rev:8 rq:548058 version:1.1.9 Changes: -------- --- /work/SRC/openSUSE:Factory/socket_wrapper/socket_wrapper.changes 2017-10-17 01:51:55.272111923 +0200 +++ /work/SRC/openSUSE:Factory/.socket_wrapper.new/socket_wrapper.changes 2017-12-05 01:30:27.432820946 +0100 @@ -1,0 +2,6 @@ +Mon Dec 4 11:22:22 UTC 2017 - [email protected] + +- Update to version 1.1.9 + * Fixed thread - signal deadlock issue + +------------------------------------------------------------------- Old: ---- socket_wrapper-1.1.8.tar.gz New: ---- socket_wrapper-1.1.9.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ socket_wrapper.spec ++++++ --- /var/tmp/diff_new_pack.bR4fzE/_old 2017-12-05 01:30:28.220792320 +0100 +++ /var/tmp/diff_new_pack.bR4fzE/_new 2017-12-05 01:30:28.224792174 +0100 @@ -24,7 +24,7 @@ ############################# NOTE ################################## Name: socket_wrapper -Version: 1.1.8 +Version: 1.1.9 Release: 0 Summary: A library passing all socket communications trough Unix sockets License: BSD-3-Clause ++++++ socket_wrapper-1.1.8.tar.gz -> socket_wrapper-1.1.9.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/CMakeLists.txt new/socket_wrapper-1.1.9/CMakeLists.txt --- old/socket_wrapper-1.1.8/CMakeLists.txt 2017-10-12 16:47:44.000000000 +0200 +++ new/socket_wrapper-1.1.9/CMakeLists.txt 2017-12-04 10:21:00.000000000 +0100 @@ -8,7 +8,7 @@ set(APPLICATION_VERSION_MAJOR "1") set(APPLICATION_VERSION_MINOR "1") -set(APPLICATION_VERSION_PATCH "8") +set(APPLICATION_VERSION_PATCH "9") set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}") @@ -19,7 +19,7 @@ # Increment AGE. Set REVISION to 0 # If the source code was changed, but there were no interface changes: # Increment REVISION. -set(LIBRARY_VERSION "0.1.8") +set(LIBRARY_VERSION "0.1.9") set(LIBRARY_SOVERSION "0") # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/ChangeLog new/socket_wrapper-1.1.9/ChangeLog --- old/socket_wrapper-1.1.8/ChangeLog 2017-10-13 08:18:59.000000000 +0200 +++ new/socket_wrapper-1.1.9/ChangeLog 2017-12-04 10:21:00.000000000 +0100 @@ -1,6 +1,9 @@ ChangeLog ========== +version 1.1.9 (released 2017-12-04) + * Fixed thread - signal deadlock issue + version 1.1.8 (released 2017-10-13) * Added support for openat() * Added support for open64() and fopen64() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/src/socket_wrapper.c new/socket_wrapper-1.1.9/src/socket_wrapper.c --- old/socket_wrapper-1.1.8/src/socket_wrapper.c 2017-09-07 07:57:43.000000000 +0200 +++ new/socket_wrapper-1.1.9/src/socket_wrapper.c 2017-12-04 10:20:52.000000000 +0100 @@ -671,37 +671,46 @@ } #define swrap_bind_symbol_libc(sym_name) \ - SWRAP_LOCK(libc_symbol_binding); \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ - swrap.libc.symbols._libc_##sym_name.obj = \ - _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \ - } \ - SWRAP_UNLOCK(libc_symbol_binding) + SWRAP_LOCK(libc_symbol_binding); \ + if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ + swrap.libc.symbols._libc_##sym_name.obj = \ + _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \ + } \ + SWRAP_UNLOCK(libc_symbol_binding); \ + } #define swrap_bind_symbol_libsocket(sym_name) \ - SWRAP_LOCK(libc_symbol_binding); \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ - swrap.libc.symbols._libc_##sym_name.obj = \ - _swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \ - } \ - SWRAP_UNLOCK(libc_symbol_binding) + SWRAP_LOCK(libc_symbol_binding); \ + if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ + swrap.libc.symbols._libc_##sym_name.obj = \ + _swrap_bind_symbol(SWRAP_LIBSOCKET, #sym_name); \ + } \ + SWRAP_UNLOCK(libc_symbol_binding); \ + } #define swrap_bind_symbol_libnsl(sym_name) \ - SWRAP_LOCK(libc_symbol_binding); \ if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ - swrap.libc.symbols._libc_##sym_name.obj = \ - _swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \ - } \ - SWRAP_UNLOCK(libc_symbol_binding) + SWRAP_LOCK(libc_symbol_binding); \ + if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \ + swrap.libc.symbols._libc_##sym_name.obj = \ + _swrap_bind_symbol(SWRAP_LIBNSL, #sym_name); \ + } \ + SWRAP_UNLOCK(libc_symbol_binding); \ + } -/* - * IMPORTANT +/**************************************************************************** + * IMPORTANT + **************************************************************************** * - * Functions especially from libc need to be loaded individually, you can't load - * all at once or gdb will segfault at startup. The same applies to valgrind and - * has probably something todo with with the linker. - * So we need load each function at the point it is called the first time. - */ + * Functions especially from libc need to be loaded individually, you can't + * load all at once or gdb will segfault at startup. The same applies to + * valgrind and has probably something todo with with the linker. So we need + * load each function at the point it is called the first time. + * + ****************************************************************************/ + #ifdef HAVE_ACCEPT4 static int libc_accept4(int sockfd, struct sockaddr *addr, @@ -1077,6 +1086,59 @@ return swrap.libc.symbols._libc_writev.f(fd, iov, iovcnt); } +/* DO NOT call this function during library initialization! */ +static void swrap_bind_symbol_all(void) +{ +#ifdef HAVE_ACCEPT4 + swrap_bind_symbol_libsocket(accept4); +#else + swrap_bind_symbol_libsocket(accept); +#endif + swrap_bind_symbol_libsocket(bind); + swrap_bind_symbol_libc(close); + swrap_bind_symbol_libsocket(connect); + swrap_bind_symbol_libc(dup); + swrap_bind_symbol_libc(dup2); + swrap_bind_symbol_libc(fcntl); + swrap_bind_symbol_libc(fopen); +#ifdef HAVE_FOPEN64 + swrap_bind_symbol_libc(fopen64); +#endif +#ifdef HAVE_EVENTFD + swrap_bind_symbol_libc(eventfd); +#endif + swrap_bind_symbol_libsocket(getpeername); + swrap_bind_symbol_libsocket(getsockname); + swrap_bind_symbol_libsocket(getsockopt); + swrap_bind_symbol_libc(ioctl); + swrap_bind_symbol_libsocket(listen); + swrap_bind_symbol_libc(open); +#ifdef HAVE_OPEN64 + swrap_bind_symbol_libc(open64); +#endif + swrap_bind_symbol_libc(openat); + swrap_bind_symbol_libsocket(pipe); + swrap_bind_symbol_libc(read); + swrap_bind_symbol_libsocket(readv); + swrap_bind_symbol_libsocket(recv); + swrap_bind_symbol_libsocket(recvfrom); + swrap_bind_symbol_libsocket(recvmsg); + swrap_bind_symbol_libsocket(send); + swrap_bind_symbol_libsocket(sendmsg); + swrap_bind_symbol_libsocket(sendto); + swrap_bind_symbol_libsocket(setsockopt); +#ifdef HAVE_SIGNALFD + swrap_bind_symbol_libsocket(signalfd); +#endif + swrap_bind_symbol_libsocket(socket); + swrap_bind_symbol_libsocket(socketpair); +#ifdef HAVE_TIMERFD_CREATE + swrap_bind_symbol_libc(timerfd_create); +#endif + swrap_bind_symbol_libc(write); + swrap_bind_symbol_libsocket(writev); +} + /********************************************************* * SWRAP HELPER FUNCTIONS *********************************************************/ @@ -1523,7 +1585,7 @@ if (addr == 0) { /* 0.0.0.0 */ - is_bcast = 0; + is_bcast = 0; type = d_type; iface = socket_wrapper_default_iface(); } else if (a_type && addr == 0xFFFFFFFF) { @@ -2344,7 +2406,7 @@ if (fd != -1) { struct swrap_file_hdr file_hdr; file_hdr.magic = 0xA1B2C3D4; - file_hdr.version_major = 0x0002; + file_hdr.version_major = 0x0002; file_hdr.version_minor = 0x0004; file_hdr.timezone = 0x00000000; file_hdr.sigfigs = 0x00000000; @@ -5835,6 +5897,15 @@ static void swrap_thread_prepare(void) { + /* + * This function should only be called here!! + * + * We bind all symobls to avoid deadlocks of the fork is + * interrupted by a signal handler using a symbol of this + * library. + */ + swrap_bind_symbol_all(); + SWRAP_LOCK_ALL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/tests/CMakeLists.txt new/socket_wrapper-1.1.9/tests/CMakeLists.txt --- old/socket_wrapper-1.1.8/tests/CMakeLists.txt 2017-09-07 07:57:43.000000000 +0200 +++ new/socket_wrapper-1.1.9/tests/CMakeLists.txt 2017-12-04 10:20:57.000000000 +0100 @@ -37,7 +37,8 @@ test_echo_udp_sendmsg_recvmsg test_swrap_unit test_max_sockets - test_close_failure) + test_close_failure + test_fork_thread_deadlock) if (HAVE_STRUCT_MSGHDR_MSG_CONTROL) set(SWRAP_TESTS ${SWRAP_TESTS} test_sendmsg_recvmsg_fd) @@ -60,3 +61,8 @@ ENVIRONMENT LD_PRELOAD=${SOCKET_WRAPPER_LOCATION}) endif() endforeach() + +# test_fork_pthread +add_library(thread_deadlock SHARED thread_deadlock.c) +target_link_libraries(thread_deadlock ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(test_fork_thread_deadlock thread_deadlock) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/tests/test_echo_tcp_bind.c new/socket_wrapper-1.1.9/tests/test_echo_tcp_bind.c --- old/socket_wrapper-1.1.8/tests/test_echo_tcp_bind.c 2016-10-20 09:01:42.000000000 +0200 +++ new/socket_wrapper-1.1.9/tests/test_echo_tcp_bind.c 2017-12-04 10:20:41.000000000 +0100 @@ -143,7 +143,7 @@ * Finally, success binding a new IPv4 address. */ addr_in = (struct torture_address) { - .sa_socklen = sizeof(struct sockaddr_un), + .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, }, @@ -156,7 +156,7 @@ assert_return_code(rc, errno); addr_in = (struct torture_address) { - .sa_socklen = sizeof(struct sockaddr_un), + .sa_socklen = sizeof(struct sockaddr_in), .sa.in = (struct sockaddr_in) { .sin_family = AF_INET, .sin_port = htons(torture_server_port()), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/tests/test_fork_thread_deadlock.c new/socket_wrapper-1.1.9/tests/test_fork_thread_deadlock.c --- old/socket_wrapper-1.1.8/tests/test_fork_thread_deadlock.c 1970-01-01 01:00:00.000000000 +0100 +++ new/socket_wrapper-1.1.9/tests/test_fork_thread_deadlock.c 2017-12-04 10:20:57.000000000 +0100 @@ -0,0 +1,98 @@ +#include "config.h" + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> + +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> + +/* + * This reproduces and issue if we get a signal after the pthread_atfork() + * prepare function of socket wrapper has been called. + * + * The order how pthread_atfork() handlers are set up is: + * -> application + * -> preloaded libraries + * -> libraries + * + * We have a library called thread_deadlock. + * + * This library registers a thread_deadlock_prepare() function via + * pthread_atfork(). + * + * So pthread_atfork() registers the prepare function in the follow order: + * -> swrap_thread_prepare() + * -> thread_deadlock_prepare() + * + * In this test we fork and the swrap_thread_prepare() locks the mutex for + * symbol binding. + * Then thread_deadlock_prepare() is called which sends a signal to the parent + * process of this test. The signal triggers the signal handler below. + * + * When we call write() in the signal handler, we will try to bind the libc symbol + * and want to lock the symbol binding mutex. As it is already locked we run into + * a deadlock. + */ + +static void test_swrap_signal_handler(int signum) +{ + fprintf(stderr, "PID: %d, SIGNUM: %d\n", getpid(), signum); + write(1, "DEADLOCK?\n", 10); +} + +static void test_swrap_fork_pthread(void **state) +{ + pid_t pid; + struct sigaction act = { + .sa_handler = test_swrap_signal_handler, + .sa_flags = 0, + }; + + (void)state; /* unused */ + + sigemptyset(&act.sa_mask); + sigaction(SIGUSR1, &act, NULL); + + pid = fork(); + assert_return_code(pid, errno); + + /* child */ + if (pid == 0) { + exit(0); + } + + /* parent */ + if (pid > 0) { + pid_t child_pid; + int wstatus = -1; + + child_pid = waitpid(-1, &wstatus, 0); + assert_return_code(child_pid, errno); + + assert_true(WIFEXITED(wstatus)); + + assert_int_equal(WEXITSTATUS(wstatus), 0); + } +} + +int main(void) +{ + int rc; + + const struct CMUnitTest swrap_tests[] = { + cmocka_unit_test(test_swrap_fork_pthread), + }; + + rc = cmocka_run_group_tests(swrap_tests, NULL, NULL); + + return rc; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/socket_wrapper-1.1.8/tests/thread_deadlock.c new/socket_wrapper-1.1.9/tests/thread_deadlock.c --- old/socket_wrapper-1.1.8/tests/thread_deadlock.c 1970-01-01 01:00:00.000000000 +0100 +++ new/socket_wrapper-1.1.9/tests/thread_deadlock.c 2017-12-04 10:20:57.000000000 +0100 @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2017 Andreas Schneider <[email protected]> + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "config.h" + +#include <stdio.h> +#include <signal.h> +#include <pthread.h> + +#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE +#define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor)) +#else +#define CONSTRUCTOR_ATTRIBUTE +#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */ + +void thread_deadlock_constructor(void) CONSTRUCTOR_ATTRIBUTE; + +static void thread_deadlock_prepare(void) +{ + pthread_kill(pthread_self(), SIGUSR1); + return; +} + +static void thread_deadlock_parent(void) +{ + return; +} + +static void thread_deadlock_child(void) +{ + return; +} + +void thread_deadlock_constructor(void) +{ + pthread_atfork(&thread_deadlock_prepare, + &thread_deadlock_parent, + &thread_deadlock_child); +}
