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 208941 Details for
Bug 309761
utrace: 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.
Testcase.
tracer-lockup-on-sighandler-kill.c (text/plain), 11.07 KB, created by
Jan Kratochvil
on 2007-09-27 19:33:52 UTC
(
hide
)
Description:
Testcase.
Filename:
MIME Type:
Creator:
Jan Kratochvil
Created:
2007-09-27 19:33:52 UTC
Size:
11.07 KB
patch
obsolete
>/* Fedora fix: https://bugzilla.redhat.com/show_bug.cgi?id=267161 */ > >// This file is part of the program FRYSK. >// >// Copyright 2007, Red Hat Inc. >// >// FRYSK is free software; you can redistribute it and/or modify it >// under the terms of the GNU General Public License as published by >// the Free Software Foundation; version 2 of the License. >// >// FRYSK is distributed in the hope that it will be useful, but >// WITHOUT ANY WARRANTY; without even the implied warranty of >// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >// General Public License for more details. >// >// You should have received a copy of the GNU General Public License >// along with FRYSK; if not, write to the Free Software Foundation, >// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. >// >// In addition, as a special exception, Red Hat, Inc. gives You the >// additional right to link the code of FRYSK with code not covered >// under the GNU General Public License ("Non-GPL Code") and to >// distribute linked combinations including the two, subject to the >// limitations in this paragraph. Non-GPL Code permitted under this >// exception must only link to the code of FRYSK through those well >// defined interfaces identified in the file named EXCEPTION found in >// the source code files (the "Approved Interfaces"). The files of >// Non-GPL Code may instantiate templates or use macros or inline >// functions from the Approved Interfaces without causing the >// resulting work to be covered by the GNU General Public >// License. Only Red Hat, Inc. may make changes or additions to the >// list of Approved Interfaces. You must obey the GNU General Public >// License in all respects for all of the FRYSK code and other code >// used in conjunction with FRYSK except the Non-GPL Code covered by >// this exception. If you modify this file, you may extend this >// exception to your version of the file, but you are not obligated to >// do so. If you do not wish to provide this exception without >// modification, you must delete this exception statement from your >// version and license this file solely under the GPL without >// exception. > >#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> > >/* WARNING: The real testing count is unbound. > Seen hit at 580000. */ >#define LOOPS 1000000 > >#if defined(__x86_64) || defined(__x86_64__) \ > || defined(__amd64) || defined(__amd64__) >#define PC_OFFSET 128 >#elif defined(__i386) || defined(__i386__) >#define PC_OFFSET 48 >#endif > >#ifdef PC_OFFSET > >int hit_do_nothing = 0; > >void >do_nothing(int signum) { > hit_do_nothing = 1; > 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; >#if 0 > int runnum = 1; >#endif > int bad = 0; > int loops; > > for (loops = 0; loops < LOOPS; loops++) { > > 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)) { >#if 0 > printf("INFO: %s: OK run # %d\n", "test_signalstep", runnum++); > fflush(stdout); >#endif > } else { > printf("ERR: %s after %d iterations: %s\n", "test_signalstep", loops, status_string(kidstat)); > fflush(stdout); > ++bad; > } > } else { > report_error("test_signalstep", "waitpid()"); > exit(2); > } > } > } > > if (bad) > { > printf ("%d bad in %d iterations: %.2f%%\n", > bad, LOOPS, 100.0 * bad / LOOPS); > return 1; > } > > return 0; >} > >#else /* !PC_OFFSET */ > >int main (void) >{ > return 77; >} >#endif /* !PC_OFFSET */
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 309761
: 208941