home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / crashme / crashme.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-01  |  12.8 KB  |  425 lines

  1. /* crashme: Create a string of random bytes and then jump to it.
  2.             crashme <nbytes> <srand> <ntrys> [nsub] */
  3.  
  4. char *crashme_version = "1.8 27-SEP-1991";
  5.  
  6. /*
  7.  *             COPYRIGHT (c) 1990, 1991 BY       *
  8.  *  GEORGE J. CARRETTE, CONCORD, MASSACHUSETTS.  *
  9.  *             ALL RIGHTS RESERVED               *
  10.  
  11. Permission to use, copy, modify, distribute and sell this software
  12. and its documentation for any purpose and without fee is hereby
  13. granted, provided that the above copyright notice appear in all copies
  14. and that both that copyright notice and this permission notice appear
  15. in supporting documentation, and that the name of the author
  16. not be used in advertising or publicity pertaining to distribution
  17. of the software without specific, written prior permission.
  18.  
  19. THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  20. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  21. HE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  22. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  23. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  24. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  25. SOFTWARE.
  26.  
  27. A signal handler is set up so that in most cases the machine exception
  28. generated by the illegal instructions, bad operands, etc in the procedure
  29. made up of random data are caught; and another round of randomness may
  30. be tried. Eventually a random instruction may corrupt the program or
  31. the machine state in such a way that the program must halt. This is
  32. a test of the robustness of the hardware/software for instruction
  33. fault handling.
  34.  
  35. Note: Running this program just a few times, using total CPU time of
  36. less than a few seconds SHOULD NOT GIVE YOU ANY CONFIDENCE in system
  37. robustness. Having it run for hours, with tens of thousands of cases
  38. would be a different thing.
  39.  
  40. Comments may be addressed to the author at GJC@MITECH.COM
  41.  
  42. See the documentation in crashme.1 or read this code for a description
  43. of command line arguments to this program.
  44.  
  45. Version Date         Description
  46. ----------------------------------------------------------------------
  47.  1.0    early 1990   initial hack.
  48.  1.1    19-SEP-1990  added more signals and an alarm to abort looping.
  49.  1.2    25-JUN-1991  added [nsub] to vfork multiple subprocesses of self.
  50.  1.3    14-AUG-1991  +nbytes malloc option, and -nsub option.
  51.  1.4    29-AUG-1991  fix +nbytes (subproc). Add time-driven nprocs. SIGINT.
  52.  1.5     3-SEP-1991  added alarm subprocess monitor to vfork_main.
  53.  1.6     5-SEP-1991  some systems don't have vfork, so use fork by default.
  54.  1.7    25-SEP-1991  verboseness level, exit summary report.
  55.  1.8      -SEP-1991  address page protection issues on badboy.
  56.  
  57. Suggested test: At least let the thing run the length of your lunch break,
  58. in this case 1 hour, 10 minutes, and 30 seconds.
  59.  
  60.   crashme +2000 666 100 1:10:30 2
  61.  
  62.  
  63.                         CRASH REPORTS
  64.  
  65. Date,               Machine              Crashme        Reported 
  66. Crashme Ver   Make    Model OS Version   Arguments      by:        
  67. ------------------------------------------------------------------------------
  68. 10-JUL-90 1.0 SUN     4/110 4.1          1000 20 200    GJC@paradigm.com
  69. 10-JUL-90 1.0 SUN     4/280 4.0.3        1000 20 200    GJC@paradigm.com
  70. 31-JUL-90 1.0 DIGITAL DECstation 3100    100 10 10000   GAVRON@ARIZONA.EDU
  71. 31-JUL-90 1.0 IBM     RT                 100 10 10000   GAVRON@ARIZONA.EDU
  72.  1-AUG-90 1.0 DIGITAL DECstation 5000    10000 230 1000 hudgens@scri.fsu.edu
  73.  3-AUG-90 1.0 Alliant FX/2800                           SJA@SIRIUS.HUT.FI
  74. 27-JUN-91 1.2 SUN     4/110 4.1.1        10 1000 10     LPH@PARADIGM.COM   
  75. 27-JUN-91 1.2 SUN     4/110 4.1.1        1000 20 200 10 LPH@PARADIGM.COM   
  76. 29-JUN-91 1.2 SUN     4/40C 4.1.1        9 29748 5877 4 jon@uk.ac.oxford.robots
  77. 29-JUN-91 1.2 SUN     4/60 4.1.1         9 29748 5877 4 jon@uk.ac.oxford.robots
  78. 29-JUN-91 1.2 SUN     4/100 4.1.1        9 29748 5877 4 jon@uk.ac.oxford.robots
  79. 29-JUN-91 1.2 SUN     4/65 4.1.1         9 29748 5877 4 jon@uk.ac.oxford.robots
  80. 18-JUL-91 1.2 SGI     Iris4d Unix 3.3.2  1000 $$ 1000 4 tsacas@ilog.ilog.fr
  81. 29-JUL-91 1.1 IBM     RS/6000 AIX 1.3    script         brandis@inf.ethz.ch
  82.  5-SEP-91 1.6 IBM     RS/6000-320 AIX 3.1.5 +2000 666 50 40:00:00 LPH
  83. 26-SEP-91 1.8 Nixdorf Targon/35 TOS3.3   script         petri@ibr.cs.tu-bs.de
  84.  
  85. Notes: Crashme V1.0 {1000 20 200} used to down the SUN 4/110. V1.2 does *not*
  86. crash SUNOS 4.1.1 on the same arguments. Although using the extra argument
  87. for subprocesses it will crash, with the console reporting:
  88. "Bad Trap, Bad Kernel Read Fault, Bus error. Reboot" 
  89.  
  90. Script means invoking file with many calls to crashme such as this:
  91. #/bin/csh
  92. crashme 1020 234 500 &
  93. crashme 394 38484 5723 &
  94. crashme 3784 474 474 &
  95. crashme 437 4747 38 &
  96. crashme 47848 4745 123 &
  97. crashme 4747 4747 3463 &
  98. crashme 474 46464 262 &
  99. crashme 37 3644 3723 &
  100. crashme 374 46464 22 &
  101. crashme 3747 464 363 &
  102. crashme 347 4747 44 &
  103. crashme 37374 374 66 &
  104. crashme 3737 474 4444 &
  105.  
  106. The 4-argument case of crashme could likely do as well as executing
  107. a script.
  108.  
  109. */
  110.  
  111.  
  112. #include <stdio.h>
  113. #include <signal.h>
  114. #include <setjmp.h>
  115. #include <time.h>
  116.  
  117. #ifdef pyr
  118. #include <sys/mman.h>
  119. #include <sys/types.h>
  120. #include <sys/param.h>
  121. #include <sys/vmmac.h>
  122. #define strchr index
  123. #endif
  124.  
  125. long nbytes,nseed,ntrys;
  126. long malloc_flag = 0;
  127. unsigned char *the_data;
  128. char *note_buffer;
  129. char *notes;
  130.  
  131. long verbose_level = 5;
  132.  
  133. void note(level)
  134.      long level;
  135. {if (level > verbose_level) return;
  136.  strcat(note_buffer,"\n");
  137.  fputs(note_buffer,stdout);}
  138.  
  139. jmp_buf again_buff;
  140.  
  141. void (*badboy)();
  142.  
  143. unsigned char *bad_malloc(n)
  144.      long n;
  145. {unsigned char *data;
  146.  data = (unsigned char *) malloc(n);
  147. #ifdef pyr
  148.  if (mprotect(((int)data/PAGSIZ)*PAGSIZ, (n/PAGSIZ+1)*PAGSIZ,
  149.           PROT_READ|PROT_WRITE|PROT_EXEC))
  150.    perror("mprotect");
  151. #endif
  152.  return(data);}
  153.  
  154. void again_handler(sig, code, scp, addr)
  155.      int sig, code;
  156.      struct sigcontext *scp;
  157.      char *addr;
  158. {char *ss;
  159.  switch(sig)
  160.    {case SIGILL: ss =   " illegal instruction"; break;
  161.     case SIGTRAP: ss =   " trace trap"; break;
  162.     case SIGFPE: ss =   " arithmetic exception"; break;
  163.     case SIGBUS: ss =  " bus error"; break;
  164.     case SIGSEGV: ss =  " segmentation violation"; break;
  165.     case SIGIOT: ss = " IOT instruction"; break;
  166.     case SIGEMT: ss = " EMT instruction"; break;
  167.     case SIGALRM: ss = " alarm clock"; break;
  168.     case SIGINT:  ss = " interrupt"; break;
  169.     default: ss = "";}
  170.  sprintf(notes,"Got signal %d%s",sig,ss);
  171.  note(5);
  172.  longjmp(again_buff,3);}
  173.  
  174. set_up_signals()
  175. {signal(SIGILL,again_handler);
  176.  signal(SIGTRAP,again_handler);
  177.  signal(SIGFPE,again_handler);
  178.  signal(SIGBUS,again_handler);
  179.  signal(SIGSEGV,again_handler);
  180.  signal(SIGIOT,again_handler);
  181.  signal(SIGEMT,again_handler);
  182.  signal(SIGALRM,again_handler);
  183.  signal(SIGINT,again_handler);}
  184.  
  185. compute_badboy()
  186. {long j,n;
  187.  n = (nbytes < 0) ? - nbytes : nbytes;
  188.  if (malloc_flag == 1)
  189.    {the_data = bad_malloc(n);
  190.     badboy = (void (*)()) the_data;}
  191.  for(j=0;j<n;++j) the_data[j] = (rand() >> 7) & 0xFF;
  192.  if (nbytes < 0)
  193.    {sprintf(notes,"Dump of %ld bytes of data",n);
  194.     note(1);
  195.     for(j=0;j<n;++j)
  196.       {fprintf(stdout,"%3d",the_data[j]);
  197.        if ((j % 20) == 19) putc('\n',stdout); else putc(' ',stdout);}
  198.     putc('\n',stdout);}}
  199.  
  200. try_one_crash()
  201. {if (nbytes > 0)
  202.    (*badboy)();
  203.  else if (nbytes == 0)
  204.    while(1);}
  205.  
  206. char *subprocess_ind = "subprocess";
  207.  
  208. main(argc,argv)
  209.      int argc; char **argv;
  210. {long nsubs,hrs,mns,scs,tflag,j,m;
  211.  note_buffer = (char *) malloc(512);
  212.  notes = note_buffer;
  213.  if ((argc == 7) &&
  214.      (strcmp(argv[6],subprocess_ind) == 0))
  215.    {sprintf(note_buffer,"Subprocess %s: ",argv[4]);
  216.     notes = note_buffer + strlen(note_buffer);
  217.     verbose_level = atol(argv[5]);
  218.     sprintf(notes,"starting");
  219.     note(3);
  220.     old_main(4,argv);}
  221.  else if (argc == 4)
  222.    old_main(4,argv);
  223.  else if ((argc == 5) || (argc == 6))
  224.    {if (argc == 6)
  225.       verbose_level = atol(argv[5]);
  226.     copyright_note(1);
  227.     if (argc < 7)
  228.       m = argc;
  229.     else
  230.       m = 6;
  231.     strcpy(notes,"crashme");
  232.     for(j=1;j<m;++j)
  233.       {strcat(notes," ");
  234.        strcat(notes,argv[j]);}
  235.     note(1);
  236.     if (strchr(argv[4],':'))
  237.       {sscanf(argv[4],"%d:%d:%d",&hrs,&mns,&scs);
  238.        tflag = 1;
  239.        nsubs = (((hrs * 60) + mns) * 60) + scs;
  240.        sprintf(notes,"Subprocess run for %d seconds (%d %02d:%02d:%02d)",
  241.            nsubs, hrs / 24, hrs % 24,mns,scs);}
  242.     else
  243.       {tflag = 0;
  244.        nsubs = atol(argv[4]);
  245.        sprintf(notes,"Creating %d crashme subprocesses",nsubs);}
  246.     note(1);
  247.     vfork_main(tflag,nsubs,argv[0],argv[1],atol(argv[2]),argv[3]);}
  248.  else
  249.    {sprintf(notes,"crashme <nbytes> <srand> <ntrys> [nsub] [verbose]");
  250.     note(0);}}
  251.  
  252. copyright_note(n)
  253.      long n;
  254. {sprintf(notes,"Crashme: (c) Copyright 1990, 1991 George J. Carrette");
  255.  note(n);
  256.  sprintf(notes,"Version: %s",crashme_version);
  257.  note(n);}
  258.  
  259. old_main(argc,argv)
  260.      int argc;
  261.      char **argv;
  262. {copyright_note(3);
  263.  nbytes = atol(argv[1]);
  264.  if (argv[1][0] == '+') malloc_flag = 1;
  265.  nseed = atol(argv[2]);
  266.  ntrys = atol(argv[3]);
  267.  sprintf(notes,"crashme %s%ld %ld %ld",
  268.      (malloc_flag == 0) ? "" : "+",nbytes,nseed,ntrys);
  269.  note(3);
  270.  if (malloc_flag == 0)
  271.    {the_data = bad_malloc((nbytes < 0) ? -nbytes : nbytes);
  272.     badboy = (void (*)()) the_data;
  273.     sprintf(notes,"Badboy at %d. 0x%X",badboy,badboy);
  274.     note(3);}
  275.  srand(nseed);
  276.  badboy_loop();}
  277.  
  278. badboy_loop()
  279. {int i;
  280.  for(i=0;i<ntrys;++i)
  281.    {compute_badboy();
  282.     if (malloc_flag == 1)
  283.       sprintf(notes,"try %ld, Badboy at %d. 0x%X",i,badboy,badboy);
  284.     else
  285.       sprintf(notes,"try %ld",i);
  286.     note(5);
  287.     if (setjmp(again_buff) == 3)
  288.       {sprintf(notes,"Barfed");
  289.        note(5);}
  290.     else
  291.       {set_up_signals();
  292.        alarm(10);
  293.        try_one_crash();
  294.        sprintf(notes,"didn't barf!");
  295.        note(5);}}}
  296.  
  297. long monitor_pid = 0;
  298. long monitor_period = 10;
  299. long monitor_limit =  18; /* 3 minute limit on a subprocess */
  300. long monitor_count = 0;
  301. long monitor_active = 0;
  302.  
  303. void monitor_fcn(sig, code, scp, addr)
  304.      int sig, code;
  305.      struct sigcontext *scp;
  306.      char *addr;
  307. {long status;
  308.  signal(SIGALRM,monitor_fcn);
  309.  alarm(monitor_period);
  310.  if (monitor_active)
  311.    {++monitor_count;
  312.     if (monitor_count >= monitor_limit)
  313.       {sprintf(notes,"time limit reached on pid %d 0x%X. using kill.",
  314.            monitor_pid,monitor_pid);
  315.        note(3);
  316.        status = kill(monitor_pid,SIGKILL);
  317.        if (status < 0)
  318.      {sprintf(notes,"failed to kill process");
  319.       note(3);}
  320.        monitor_active = 0;}}}
  321.  
  322. struct status_list
  323. {long status;
  324.  long count;
  325.  struct status_list *next;};
  326.  
  327. struct status_list *slist = NULL;
  328.  
  329. record_status(n)
  330.      long n;
  331. {struct status_list *l;
  332.  for(l=slist;l != NULL; l = l->next)
  333.    if (n == l->status)
  334.      return(++l->count);
  335.  l = (struct status_list *) malloc(sizeof(struct status_list));
  336.  l->count = 1;
  337.  l->status = n;
  338.  l->next = slist;
  339.  slist = l;
  340.  return(1);}
  341.  
  342. summarize_status()
  343. {struct status_list *l;
  344.  sprintf(notes,"exit status ... number of cases");
  345.  note(2);
  346.  for(l=slist;l != NULL; l = l->next)
  347.    {sprintf(notes,"exit status ... number of cases");
  348.     sprintf(notes,"%11d ... %5d",l->status,l->count);
  349.     note(2);}}
  350.  
  351. vfork_main(tflag,nsubs,cmd,nb,sr,nt)
  352.      long tflag,nsubs,sr;
  353.      char *cmd,*nb,*nt;
  354. {long j,status,pid,n,seq,total_time,dys,hrs,mns,scs;
  355.  char arg2[20],arg4[20],arg5[20];
  356.  time_t before_time,after_time;
  357.  if (tflag == 1)
  358.    {seq = 1;
  359.     n = 100000000;}
  360.  else if (nsubs < 0)
  361.    {n = -nsubs;
  362.     seq = 1;}
  363.  else
  364.    {n = nsubs;
  365.     seq = 0;}
  366.  if (seq == 1)
  367.    {signal(SIGALRM,monitor_fcn);
  368.     alarm(monitor_period);}
  369.  time(&before_time);
  370.  sprintf(arg5,"%d",verbose_level);
  371.  for(j=0;j<n;++j)
  372.    {sprintf(arg2,"%d",sr+j);
  373.     sprintf(arg4,"%d",j+1);
  374. #ifdef VMS
  375.     status = vfork();
  376. #else
  377.     status = fork();
  378. #endif
  379.     if (status == 0)
  380.       {status = execl(cmd,cmd,nb,arg2,nt,arg4,arg5,subprocess_ind,0);
  381.        if (status == -1)
  382.      {perror(cmd);
  383.       exit(1);}}
  384.     else if (status < 0)
  385.       perror(cmd);
  386.     else
  387.       {sprintf(notes,"pid = %d 0x%X (subprocess %d)",status,status,j+1);
  388.        note(3);
  389.        if (seq == 1)
  390.      {monitor_pid = status;
  391.       monitor_count = 0;
  392.       monitor_active = 1;
  393.       while((pid = wait(&status)) > 0)
  394.         {monitor_active = 0;
  395.          sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status);
  396.          note(3);
  397.          record_status(status);}}
  398.        if (tflag == 1)
  399.      {time(&after_time);
  400.       total_time = after_time - before_time;
  401.       if (total_time >= nsubs)
  402.         {sprintf(notes,"Time limit reached after run %d",j+1);
  403.          note(2);
  404.          break;}}}}
  405.  if (seq == 0)
  406.    while((pid = wait(&status)) > 0)
  407.      {sprintf(notes,"pid %d 0x%X exited with status %d",pid,pid,status);
  408.       note(3);
  409.       record_status(status);}
  410.  time(&after_time);
  411.  total_time = after_time - before_time;
  412.  scs = total_time;
  413.  mns = scs / 60;
  414.  hrs = mns / 60;
  415.  dys = hrs / 24;
  416.  scs = scs % 60;
  417.  mns = mns % 60;
  418.  hrs = hrs % 24;
  419.  sprintf(notes,
  420.      "Test complete, total real time: %d seconds (%d %02d:%02d:%02d)",
  421.      total_time,dys,hrs,mns,scs);
  422.  note(1);
  423.  summarize_status();}
  424.  
  425.