Subject: bin/3585: csh "time" bug
To: None <gnats-bugs@gnats.netbsd.org>
From: Erik E. Fair <fair@atomic.clock.org>
List: netbsd-bugs
Date: 05/08/1997 02:05:39
>Number: 3585
>Category: bin
>Synopsis: csh "time" prints negative CPU percentage for jobs with more tahn 6 hours of CPU (int overflow)
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu May 8 02:20:01 1997
>Last-Modified:
>Originator: Erik E. Fair
>Organization:
International Organization of Internet Clock Watchers
>Release: NetBSD-current of May 7, 1997
>Environment:
System: NetBSD atomic.clock.org 1.2D NetBSD 1.2D (GENERIC) #42: Wed Apr 23 08:06:27 PDT 1997 root@atomic.clock.org:/usr/src/sys/arch/sparc/compile/GENERIC sparc
>Description:
The percentage calculation in /usr/src/bin/csh/time.c (prusage)
overflows a 32-bit int if total CPU time is more than 21475 seconds.
>How-To-Repeat:
% time job-that-takes-long-enough
21541.6u 5628.2s 8:13:33.08 -53.-2% 0+0k 54448+184212io 342848pf+0w
>Fix:
*** time.c.orig Tue Jan 14 04:06:02 1997
--- time.c Thu May 8 01:53:00 1997
***************
*** 56,61 ****
--- 56,63 ----
*/
static void pdeltat __P((struct timeval *, struct timeval *));
+ extern char * strpct __P((u_long num, u_long denom, u_int digits));
+
void
settimes()
{
***************
*** 173,181 ****
case 'P': /* percent time spent running */
/* check if it did not run at all */
! i = (ms == 0) ? 0 : (t * 1000 / ms);
! /* nn.n% */
! (void) fprintf(cshout, "%ld.%01ld%%", i / 10, i % 10);
break;
case 'W': /* number of swaps */
--- 175,185 ----
case 'P': /* percent time spent running */
/* check if it did not run at all */
! if (ms == 0) {
! (void) fputs("0.0%", cshout);
! } else {
! (void) fputs(strpct((ulong)t, (ulong)ms, 1), cshout);
! }
break;
case 'W': /* number of swaps */
## New File: strpct.c (suggested for C library) ##############################
#include <stdio.h>
#include <machine/limits.h>
#include <sys/types.h>
/*
** Calculate a percentage without resorting to floating point
** and return a pointer to a string
**
** "digits" is the number of digits past the decimal place you want
** (zero being the straight percentage with no decimals)
**
** Erik E. Fair <fair@clock.org>, May 8, 1997
*/
extern char * strpct(u_long num, u_long denom, u_int digits);
char *
strpct(numerator, denominator, digits)
u_long numerator, denominator;
u_int digits;
{
register int i;
u_long result, factor = 100L;
static char percent[32];
/* I should check for digit overflow here, too XXX */
for(i = 0; i < digits; i++) {
factor *= 10;
}
/* watch out for overflow! */
if (numerator < (ULONG_MAX / factor)) {
numerator *= factor;
} else {
/* toss some of the bits of lesser significance */
denominator /= factor;
}
/* divide by zero is just plain bad */
if (denominator == 0L) {
denominator = 1L;
}
result = numerator / denominator;
if (digits == 0) {
(void) snprintf(percent, sizeof(percent), "%lu%%", result);
} else {
char fmt[32];
/* indirection to produce the right output format */
(void) snprintf(fmt, sizeof(fmt), "%%lu.%%0%ulu%%%%", digits);
factor /= 100L; /* undo initialization */
(void) snprintf(percent, sizeof(percent),
fmt, result / factor, result % factor);
}
return(percent);
}
>Audit-Trail:
>Unformatted: