Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 184741 Details for
Bug 267161
ptrace operations create unkillable process eating 100% cpu
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
new version of step-hang.c program
step-hang.c (text/plain), 8.49 KB, created by
Tom Horsley
on 2007-09-02 02:19:47 UTC
(
hide
)
Description:
new version of step-hang.c program
Filename:
MIME Type:
Creator:
Tom Horsley
Created:
2007-09-02 02:19:47 UTC
Size:
8.49 KB
patch
obsolete
>#include <stdio.h> >#include <string.h> >#include <signal.h> >#include <sys/types.h> >#include <unistd.h> >#include <sys/wait.h> >#include <sys/ptrace.h> >#include <errno.h> >#include <stdlib.h> > >#if defined(__x86_64) || defined(__x86_64__) \ > || defined(__amd64) || defined(__amd64__) >#define PC_OFFSET 128 >#endif >#ifdef __i386 >#define PC_OFFSET 48 >#endif > >bool hit_do_nothing = false; > >void >do_nothing(int signum) { > hit_do_nothing = true; > return; >} > >void >report_error(char * name, char * func) { > int errnum = errno; > printf("ERR: %s %s call failed: %s (errno = %d)\n", > name, func, strerror(errnum), errnum); > fflush(stdout); >} > >void >fatal_error(char * name, char * func) { > report_error(name, func); > exit(2); >} > >// On some versions of linux kill() isn't good enough to kill a debugged >// child. This routine does both a PTRACE_KILL and a kill() to make >// doubly sure :-). > >void >kill_kid_dead(pid_t kid) { > ptrace(PTRACE_KILL, kid, 0, 0); > kill(kid, 9); >} > >char * >status_string(int kidstat) { > static char rval[512]; > if (WIFEXITED(kidstat)) { > if (WEXITSTATUS(kidstat) == 0) { > sprintf(rval, "exited normally"); > } else { > sprintf(rval, "exited with status %d", WEXITSTATUS(kidstat)); > } > } else if (WIFSIGNALED(kidstat)) { > sprintf(rval, "terminated with signum %d", WTERMSIG(kidstat)); > } else if (WIFSTOPPED(kidstat)) { > sprintf(rval, "stopped with signum %d", WSTOPSIG(kidstat)); > } else { > sprintf(rval, "unrecognized status %#x", kidstat); > } > return rval; >} > >// Single step a child and pass in a signal. See if we wind up in the handler >// or if the handler runs, then we step. >// >void >test_signalstep() { > pid_t debugged_kid = fork(); > if (debugged_kid == 0) { > > int i; > int x; > > // This is the child. It wants to be debugged, so it needs to > // say so. > > if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) { > fatal_error("test_signalstep child", "ptrace(PTRACE_TRACEME)"); > } > > struct sigaction act; > memset((void *)&act, 0, sizeof(act)); > act.sa_handler = do_nothing; > if (sigaction(SIGUSR1, &act, NULL) == -1) { > fatal_error("test_signalstep child", "sigaction(SIGUSR1)"); > } > if (kill(getpid(), SIGUSR1) == -1) { > fatal_error("test_signalstep child", "kill(SIGUSR1)"); > } > > hit_do_nothing = 0; > x = 0; > for (i = 0; i < 1000; ++i) { > x = x + i; > } > > exit(0); > } else if (debugged_kid == (pid_t)-1) { > fatal_error("test_signalstep", "fork()"); > } else { > > int i; > > int waitstat; > if (waitpid(debugged_kid, &waitstat, WUNTRACED|__WALL) != debugged_kid) { > fatal_error("test_signalstep", "waitpid()"); > } > printf("INFO: test_signalstep pid %d status: %s\n", > debugged_kid, status_string(waitstat)); > fflush(stdout); > > // Now single step the process a few times to well past the > // kill() where it sent itself a SIGUSR1. > > for (i = 0; i < 3; ++i) { > if (ptrace(PTRACE_SINGLESTEP, debugged_kid, 0, 0) == -1) { > fatal_error("test_signalstep", "ptrace(PTRACE_SINGLESTEP)"); > } > if (waitpid(debugged_kid, &waitstat, WUNTRACED|__WALL) != debugged_kid) { > fatal_error("test_signalstep", "waitpid()"); > } > printf("INFO: test_signalstep pid %d status: %s\n", > debugged_kid, status_string(waitstat)); > fflush(stdout); > } > > // Now single step, passing the SIGUSR1 signal and see if we wind up > // at the signal handler, or at the next instruction. > > if (ptrace(PTRACE_SINGLESTEP, debugged_kid, 0, SIGUSR1) == -1) { > fatal_error("test_signalstep", "ptrace(PTRACE_SINGLESTEP)"); > } > if (waitpid(debugged_kid, &waitstat, WUNTRACED|__WALL) != debugged_kid) { > fatal_error("test_signalstep", "waitpid()"); > } > printf("INFO: test_signalstep pid %d status: %s\n", > debugged_kid, status_string(waitstat)); > fflush(stdout); > > // Where is PC? > > long pcval = ptrace(PTRACE_PEEKUSER, debugged_kid, (void *)PC_OFFSET, 0); > if (pcval == -1) { > fatal_error("test_signalstep", "ptrace(PTRACE_PEEKUSER)"); > } > printf("INFO: test_signalstep pid %d PC = 0x%lx\n", > debugged_kid, pcval); > if (((unsigned long)pcval) == (unsigned long)&do_nothing) { > printf("DEF: STEP_INTO_HANDLER=1\n"); > } else { > printf("DEF: STEP_INTO_HANDLER=0\n"); > } > printf("INFO: calling kill_kid_dead(%d)\n", debugged_kid); > fflush(stdout); > kill_kid_dead(debugged_kid); > printf("INFO: returned from kill_kid_dead(%d)\n", debugged_kid); > fflush(stdout); > > // If this waitpid() call isn't done, sometimes I hang > // forever eating 100% of a cpu. > >#ifdef DO_NOT_HANG > if (waitpid(debugged_kid, &waitstat, WUNTRACED|__WALL) != debugged_kid) { > fatal_error("test_signalstep", "waitpid()"); > } >#endif > } >} > >int >main(int argc, char ** argv) { > > // We don't want any nasy signals when children exit or pipes > // close abnormally. > > sigset_t maskoff; > sigemptyset(&maskoff); > sigaddset(&maskoff, SIGCHLD); > sigaddset(&maskoff, SIGPIPE); > sigprocmask(SIG_BLOCK, &maskoff, NULL); > > // But I do want SIGUSR1 signals. > > sigemptyset(&maskoff); > sigaddset(&maskoff, SIGUSR1); > sigprocmask(SIG_UNBLOCK, &maskoff, NULL); > > char buf[10000]; > int buflen; > int runnum = 1; > > for ( ; ; ) { > > int p[2]; > if (pipe(p) != 0) { > report_error("test_signalstep", "pipe()"); > exit(2); > } > fflush(stdout); > fflush(stderr); > > // Keep running test in a new kid till one of 'em gets hung... > > buflen = 0; > pid_t kid = fork(); > if (kid == (pid_t)-1) { > report_error("test_signalstep", "fork()"); > close(p[0]); > close(p[1]); > exit(2); > } > if (kid == 0) { > > // In the child, we want to swap in the p[1] file descriptor > // as stdout and stderr so the parent can accumulate anything > // we have to say by reading p[0] > > close(p[0]); > if (dup2(p[1], fileno(stdout)) != fileno(stdout)) { > exit(1); > } > if (dup2(p[1], fileno(stderr)) != fileno(stderr)) { > exit(2); > } > close(p[1]); > > // Now run the test > > test_signalstep(); > > // And exit from the child normally (if we get back here :-) > > exit(0); > } else { > > // In this parent, all we do is read p[0] and accumulate it in > // buf. However, we expect to see an eof within a few seconds, or > // we assume the test is hung. > > close(p[1]); > for ( ; ; ) { > fd_set readfd; > struct timeval tmout; > FD_ZERO(&readfd); > FD_SET(p[0], &readfd); > memset((void *)&tmout, 0, sizeof(tmout)); > tmout.tv_sec = 10; // 10 seconds should be an etrnity... > int selstat = select(p[0] + 1, &readfd, NULL, NULL, &tmout); > if (selstat == 0) { > printf("We have a weiner!\n" > "The test_signalstep child pid %d is apparently hung.\n" > "The bug has been reproduced!\n", kid); > buf[buflen] = '\0'; > printf("Accumulated output from test:\n%s\n", buf); > fflush(stdout); > exit(2); > } else if (selstat == -1) { > report_error("test_signalstep", "select()"); > kill(kid, 9); > exit(2); > } else { > int readlen = read(p[0], &buf[buflen], sizeof(buf) - buflen); > if (readlen == 0) { > // EOF - kid must have exited normally - no hang > break; > } else if (readlen == -1) { > report_error("test_signalstep", "read()"); > kill(kid, 9); > exit(2); > } > buflen += readlen; > } > } > close(p[0]); > int kidstat; > pid_t waitstat = waitpid(kid, &kidstat, 0); > if (waitstat == kid) { > if (WIFEXITED(kidstat) && (WEXITSTATUS(kidstat) == 0)) { > printf("INFO: %s: OK run # %d\n", "test_signalstep", runnum++); > fflush(stdout); > } else { > printf("ERR: %s: %s\n", "test_signalstep", status_string(kidstat)); > fflush(stdout); > } > } else { > report_error("test_signalstep", "waitpid()"); > exit(2); > } > } > } >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 267161
:
181121
| 184741