8008088: SA can hang the VM

Wed, 13 Feb 2013 09:46:19 +0100

author
rbackman
date
Wed, 13 Feb 2013 09:46:19 +0100
changeset 4599
2394a89e89f4
parent 4598
7adae9244bc8
child 4600
49618582fc5b

8008088: SA can hang the VM
Reviewed-by: mgronlun, sla, dholmes

agent/src/os/bsd/libproc_impl.c file | annotate | diff | comparison | revisions
agent/src/os/bsd/libproc_impl.h file | annotate | diff | comparison | revisions
agent/src/os/bsd/ps_proc.c file | annotate | diff | comparison | revisions
agent/src/os/linux/libproc_impl.c file | annotate | diff | comparison | revisions
agent/src/os/linux/libproc_impl.h file | annotate | diff | comparison | revisions
agent/src/os/linux/ps_proc.c file | annotate | diff | comparison | revisions
     1.1 --- a/agent/src/os/bsd/libproc_impl.c	Wed Feb 13 11:23:46 2013 +0100
     1.2 +++ b/agent/src/os/bsd/libproc_impl.c	Wed Feb 13 09:46:19 2013 +0100
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -91,6 +91,14 @@
    1.11     }
    1.12  }
    1.13  
    1.14 +void print_error(const char* format,...) {
    1.15 +  va_list alist;
    1.16 +  va_start(alist, format);
    1.17 +  fputs("ERROR: ", stderr);
    1.18 +  vfprintf(stderr, format, alist);
    1.19 +  va_end(alist);
    1.20 +}
    1.21 +
    1.22  bool is_debug() {
    1.23     return _libsaproc_debug;
    1.24  }
     2.1 --- a/agent/src/os/bsd/libproc_impl.h	Wed Feb 13 11:23:46 2013 +0100
     2.2 +++ b/agent/src/os/bsd/libproc_impl.h	Wed Feb 13 09:46:19 2013 +0100
     2.3 @@ -1,5 +1,5 @@
     2.4  /*
     2.5 - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
     2.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     2.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8   *
     2.9   * This code is free software; you can redistribute it and/or modify it
    2.10 @@ -107,6 +107,7 @@
    2.11  int pathmap_open(const char* name);
    2.12  
    2.13  void print_debug(const char* format,...);
    2.14 +void print_error(const char* format,...);
    2.15  bool is_debug();
    2.16  
    2.17  typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid);
     3.1 --- a/agent/src/os/bsd/ps_proc.c	Wed Feb 13 11:23:46 2013 +0100
     3.2 +++ b/agent/src/os/bsd/ps_proc.c	Wed Feb 13 09:46:19 2013 +0100
     3.3 @@ -1,5 +1,5 @@
     3.4  /*
     3.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
     3.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     3.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.8   *
     3.9   * This code is free software; you can redistribute it and/or modify it
    3.10 @@ -129,42 +129,66 @@
    3.11    return (errno == 0)? true: false;
    3.12  }
    3.13  
    3.14 +static bool ptrace_continue(pid_t pid, int signal) {
    3.15 +  // pass the signal to the process so we don't swallow it
    3.16 +  if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) {
    3.17 +    print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid);
    3.18 +    return false;
    3.19 +  }
    3.20 +  return true;
    3.21 +}
    3.22 +
    3.23 +// waits until the ATTACH has stopped the process
    3.24 +// by signal SIGSTOP
    3.25 +static bool ptrace_waitpid(pid_t pid) {
    3.26 +  int ret;
    3.27 +  int status;
    3.28 +  do {
    3.29 +    // Wait for debuggee to stop.
    3.30 +    ret = waitpid(pid, &status, 0);
    3.31 +    if (ret >= 0) {
    3.32 +      if (WIFSTOPPED(status)) {
    3.33 +        // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
    3.34 +        // will still be pending and delivered when the process is DETACHED and the process
    3.35 +        // will go to sleep.
    3.36 +        if (WSTOPSIG(status) == SIGSTOP) {
    3.37 +          // Debuggee stopped by SIGSTOP.
    3.38 +          return true;
    3.39 +        }
    3.40 +        if (!ptrace_continue(pid, WSTOPSIG(status))) {
    3.41 +          print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
    3.42 +          return false;
    3.43 +        }
    3.44 +      } else {
    3.45 +        print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
    3.46 +        return false;
    3.47 +      }
    3.48 +    } else {
    3.49 +      switch (errno) {
    3.50 +        case EINTR:
    3.51 +          continue;
    3.52 +          break;
    3.53 +        case ECHILD:
    3.54 +          print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
    3.55 +          break;
    3.56 +        case EINVAL:
    3.57 +          print_debug("waitpid() failed. Invalid options argument.\n");
    3.58 +          break;
    3.59 +        default:
    3.60 +          print_debug("waitpid() failed. Unexpected error %d\n",errno);
    3.61 +      }
    3.62 +      return false;
    3.63 +    }
    3.64 +  } while(true);
    3.65 +}
    3.66 +
    3.67  // attach to a process/thread specified by "pid"
    3.68  static bool ptrace_attach(pid_t pid) {
    3.69    if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) {
    3.70      print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
    3.71      return false;
    3.72    } else {
    3.73 -    int ret;
    3.74 -    int status;
    3.75 -    do {
    3.76 -      // Wait for debuggee to stop.
    3.77 -      ret = waitpid(pid, &status, 0);
    3.78 -      if (ret >= 0) {
    3.79 -        if (WIFSTOPPED(status)) {
    3.80 -          // Debuggee stopped.
    3.81 -          return true;
    3.82 -        } else {
    3.83 -          print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
    3.84 -          return false;
    3.85 -        }
    3.86 -      } else {
    3.87 -        switch (errno) {
    3.88 -          case EINTR:
    3.89 -            continue;
    3.90 -            break;
    3.91 -          case ECHILD:
    3.92 -            print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
    3.93 -            break;
    3.94 -          case EINVAL:
    3.95 -            print_debug("waitpid() failed. Invalid options argument.\n");
    3.96 -            break;
    3.97 -          default:
    3.98 -            print_debug("waitpid() failed. Unexpected error %d\n",errno);
    3.99 -        }
   3.100 -        return false;
   3.101 -      }
   3.102 -    } while(true);
   3.103 +    return ptrace_waitpid(pid);
   3.104    }
   3.105  }
   3.106  
     4.1 --- a/agent/src/os/linux/libproc_impl.c	Wed Feb 13 11:23:46 2013 +0100
     4.2 +++ b/agent/src/os/linux/libproc_impl.c	Wed Feb 13 09:46:19 2013 +0100
     4.3 @@ -1,5 +1,5 @@
     4.4  /*
     4.5 - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
     4.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     4.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.8   *
     4.9   * This code is free software; you can redistribute it and/or modify it
    4.10 @@ -92,6 +92,14 @@
    4.11     }
    4.12  }
    4.13  
    4.14 +void print_error(const char* format,...) {
    4.15 +  va_list alist;
    4.16 +  va_start(alist, format);
    4.17 +  fputs("ERROR: ", stderr);
    4.18 +  vfprintf(stderr, format, alist);
    4.19 +  va_end(alist);
    4.20 +}
    4.21 +
    4.22  bool is_debug() {
    4.23     return _libsaproc_debug;
    4.24  }
     5.1 --- a/agent/src/os/linux/libproc_impl.h	Wed Feb 13 11:23:46 2013 +0100
     5.2 +++ b/agent/src/os/linux/libproc_impl.h	Wed Feb 13 09:46:19 2013 +0100
     5.3 @@ -1,5 +1,5 @@
     5.4  /*
     5.5 - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
     5.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     5.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.8   *
     5.9   * This code is free software; you can redistribute it and/or modify it
    5.10 @@ -105,6 +105,7 @@
    5.11  int pathmap_open(const char* name);
    5.12  
    5.13  void print_debug(const char* format,...);
    5.14 +void print_error(const char* format,...);
    5.15  bool is_debug();
    5.16  
    5.17  typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid);
     6.1 --- a/agent/src/os/linux/ps_proc.c	Wed Feb 13 11:23:46 2013 +0100
     6.2 +++ b/agent/src/os/linux/ps_proc.c	Wed Feb 13 09:46:19 2013 +0100
     6.3 @@ -1,5 +1,5 @@
     6.4  /*
     6.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
     6.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     6.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.8   *
     6.9   * This code is free software; you can redistribute it and/or modify it
    6.10 @@ -25,6 +25,7 @@
    6.11  #include <stdio.h>
    6.12  #include <stdlib.h>
    6.13  #include <string.h>
    6.14 +#include <signal.h>
    6.15  #include <errno.h>
    6.16  #include <sys/ptrace.h>
    6.17  #include "libproc_impl.h"
    6.18 @@ -142,46 +143,71 @@
    6.19  
    6.20  }
    6.21  
    6.22 +static bool ptrace_continue(pid_t pid, int signal) {
    6.23 +  // pass the signal to the process so we don't swallow it
    6.24 +  if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) {
    6.25 +    print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid);
    6.26 +    return false;
    6.27 +  }
    6.28 +  return true;
    6.29 +}
    6.30 +
    6.31 +// waits until the ATTACH has stopped the process
    6.32 +// by signal SIGSTOP
    6.33 +static bool ptrace_waitpid(pid_t pid) {
    6.34 +  int ret;
    6.35 +  int status;
    6.36 +  while (true) {
    6.37 +    // Wait for debuggee to stop.
    6.38 +    ret = waitpid(pid, &status, 0);
    6.39 +    if (ret == -1 && errno == ECHILD) {
    6.40 +      // try cloned process.
    6.41 +      ret = waitpid(pid, &status, __WALL);
    6.42 +    }
    6.43 +    if (ret >= 0) {
    6.44 +      if (WIFSTOPPED(status)) {
    6.45 +        // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
    6.46 +        // will still be pending and delivered when the process is DETACHED and the process
    6.47 +        // will go to sleep.
    6.48 +        if (WSTOPSIG(status) == SIGSTOP) {
    6.49 +          // Debuggee stopped by SIGSTOP.
    6.50 +          return true;
    6.51 +        }
    6.52 +        if (!ptrace_continue(pid, WSTOPSIG(status))) {
    6.53 +          print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
    6.54 +          return false;
    6.55 +        }
    6.56 +      } else {
    6.57 +        print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
    6.58 +        return false;
    6.59 +      }
    6.60 +    } else {
    6.61 +      switch (errno) {
    6.62 +        case EINTR:
    6.63 +          continue;
    6.64 +          break;
    6.65 +        case ECHILD:
    6.66 +          print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
    6.67 +          break;
    6.68 +        case EINVAL:
    6.69 +          print_debug("waitpid() failed. Invalid options argument.\n");
    6.70 +          break;
    6.71 +        default:
    6.72 +          print_debug("waitpid() failed. Unexpected error %d\n",errno);
    6.73 +          break;
    6.74 +      }
    6.75 +      return false;
    6.76 +    }
    6.77 +  }
    6.78 +}
    6.79 +
    6.80  // attach to a process/thread specified by "pid"
    6.81  static bool ptrace_attach(pid_t pid) {
    6.82    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
    6.83      print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
    6.84      return false;
    6.85    } else {
    6.86 -    int ret;
    6.87 -    int status;
    6.88 -    do {
    6.89 -      // Wait for debuggee to stop.
    6.90 -      ret = waitpid(pid, &status, 0);
    6.91 -      if (ret == -1 && errno == ECHILD) {
    6.92 -        // try cloned process.
    6.93 -        ret = waitpid(pid, &status, __WALL);
    6.94 -      }
    6.95 -      if (ret >= 0) {
    6.96 -        if (WIFSTOPPED(status)) {
    6.97 -          // Debuggee stopped.
    6.98 -          return true;
    6.99 -        } else {
   6.100 -          print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
   6.101 -          return false;
   6.102 -        }
   6.103 -      } else {
   6.104 -        switch (errno) {
   6.105 -          case EINTR:
   6.106 -            continue;
   6.107 -            break;
   6.108 -          case ECHILD:
   6.109 -            print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
   6.110 -            break;
   6.111 -          case EINVAL:
   6.112 -            print_debug("waitpid() failed. Invalid options argument.\n");
   6.113 -            break;
   6.114 -          default:
   6.115 -            print_debug("waitpid() failed. Unexpected error %d\n",errno);
   6.116 -        }
   6.117 -        return false;
   6.118 -      }
   6.119 -    } while(true);
   6.120 +    return ptrace_waitpid(pid);
   6.121    }
   6.122  }
   6.123  

mercurial