Mysterious hang in __sanitizer::internal_sched_yield

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I have a nearly-reduced test case which livelocks fairly predictably,
but only on Ubuntu 18.04, not on 19.10 or 20.04 alpha.

gcc --version reports
  gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0

The script

#!/bin/sh
set -ex
gcc -g -O2 -fsanitize=address -pthread bug.i -lssl -o bug
export ASAN_OPTIONS=detect_stack_use_after_return=1
export LSAN_OPTIONS=verbosity=1
for iter in $(seq 1 1000)
do
  ./bug
done
echo "No hang found."

triggers the hang reliably for me in under a minute.  Now that I know turning
off LSAN_OPTIONS=verbosity=1 makes the hang go away, I'm not
really worried about it, but I am still wondering why the problem goes
away in ubuntu 19.10.  (Was it an accidental fix, or is this a known bug that
has been fixed?)

ps shows the test case using all of one core:

buildbot 20292 98.3  0.0 21474948752 11116 pts/4 Rl+ 22:12   0:58 ./bug

gdb bt shows

__sanitizer::internal_sched_yield () at
../../../../src/libsanitizer/sanitizer_common/sanitizer_linux.cc:332
332     ../../../../src/libsanitizer/sanitizer_common/sanitizer_linux.cc:
No such file or directory.
#0  __sanitizer::internal_sched_yield () at
../../../../src/libsanitizer/sanitizer_common/sanitizer_linux.cc:332
#1  0x00007f7d348a6e95 in __interceptor_pthread_create
(thread=0x7f7d2fb00060, attr=<optimized out>,
    start_routine=0x55b8cb83b470 <thread_main>, arg=0x0) at
../../../../src/libsanitizer/asan/asan_interceptors.cc:273
#2  0x000055b8cb83b67d in do_work () at bug.c:48
#3  0x000055b8cb83b28d in create_children () at bug.c:88
#4  main (argc=<optimized out>, argv=<optimized out>) at bug.c:106

I suppose I could finish reducing the test case by pulling the source
for SSL_CTX_new() into my .i and letting c-reduce run wild, but first
I thought I'd ask if this rings a bell.

Here's the mostly-reduced test case.

-- snip --
static int readers = 40;
static int once_control = 0;
static int test_secs = 1;

typedef int pid_t;
struct timeval {
  long tv_sec;
  long tv_usec;
};
struct timespec {
  long tv_sec;
  long tv_nsec;
};
typedef unsigned long int pthread_t;
enum __itimer_which {
  ITIMER_REAL,
};
struct itimerval {
  struct timeval it_interval;
  struct timeval it_value;
};
typedef int sig_atomic_t;
typedef void(*__sighandler_t);
struct sigaction {
  struct {
    __sighandler_t sa_handler;
  } __sigaction_handler;
};

typedef struct ssl_ctx_st SSL_CTX;
typedef struct ssl_method_st SSL_METHOD;
static SSL_CTX *context;

static struct timespec start_time;
static struct timespec goal_end_time;
static volatile sig_atomic_t keep_on_chugging = 1;

void do_once() {
  const struct ssl_method_st *p = 0;
  SSL_CTX *context = SSL_CTX_new(p);
}

void thread_main(void *v) { }

void do_work() {
  pthread_t net_5;
  pthread_once(&once_control, do_once);
  pthread_create(&net_5, 0, thread_main, 0);
}

static _Bool is_time_to_quit(void) {
  struct timespec now_time;
  clock_gettime(0, &now_time);
  long long remaining_nsecs =
      (goal_end_time.tv_sec - now_time.tv_sec) * 1000000000ULL;
  remaining_nsecs += goal_end_time.tv_nsec - now_time.tv_nsec;
  if (remaining_nsecs < 0) return 1;
  return 0;
}

static void set_flag_for_exit(int signo) {
  if (is_time_to_quit()) keep_on_chugging = 0;
}

static void set_timer(void) {
  struct itimerval iv = {{0}, {0}};
  iv.it_value.tv_usec = 3000;
  iv.it_interval.tv_usec = 3000;
  if (setitimer(ITIMER_REAL, &iv, ((void *)0)) < 0)
    abort();
  if (is_time_to_quit()) exit(0);
}

static void create_children(void) {
  int i;
  struct sigaction act;
  memset(&act, 0, sizeof(act));
  act.__sigaction_handler.sa_handler = set_flag_for_exit;
  sigaction(14, &act, ((void *)0));
  act.__sigaction_handler.sa_handler = ((__sighandler_t)1);
  pid_t pid;
  for (i = 0; i < readers; i++) {
    if (i < readers) {
      if ((pid = fork()) < 0)
        abort();
      if (pid == 0) {
        set_timer();
        do_work();
        _exit(0);
      }
    }
  }
}

static int reap_children(void) {
  int i;
  int status;
  for (i = 0; i < readers; i++) wait(&status);
}

int main(int argc, char *argv[]) {
  clock_gettime(0, &start_time);
  goal_end_time = start_time;
  goal_end_time.tv_sec += test_secs;

  create_children();
  reap_children();
}

-- snip --



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux