Subject: bin/852: Hardware dependency in /usr/sbin/sa
To: None <gnats-admin@NetBSD.ORG>
From: Peter Svensson (Local) <petersv@piau.df.lth.se>
List: netbsd-bugs
Date: 03/08/1995 12:50:05
>Number:         852
>Category:       bin
>Synopsis:       /usr/sbin/sa relies on byte granularity for ints.
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Mar  8 12:50:03 1995
>Originator:     Peter Svensson (Local)
>Organization:
"YACC - Computer Society at Lund University and Lund Institute of Technology"
>Release:        940305 <NetBSD-current source date>
>Environment:
	
System: NetBSD piau.df.lth.se 1.0A NetBSD 1.0A (PIAU.SCSI) #2: Thu Jan 19 13:46:27 PST 1995 petersv@piau.df.lth.se:/usr/src/sys/arch/sparc/compile/PIAU.SCSI sparc


>Description:
The database management routines in /usr/sbin/sa relies on the host machine 
to allow byte-aligned access to ints. This is due to the fact that 
structs stored in the database are used without proper checking of their 
alignment. The database routines seem to return data extracted from it as 
an unaligned array of chars. After the typecast to a pointer to a struct 
the alignement rules are no longer necessarily observed.

This causes intermittent Bus Errors on at least Sparc-based computers.
	
>How-To-Repeat:
Run /usr/sbin/sa on a Sparc-based computer. At least SparcStation 1 is 
known to exhibit this behaviour.
	
>Fix:
I have made a workaround by replacing pointers to the critical structs 
everywhere with actuial structs on the local stack. The data is copied 
from the original pointed-to-struct prior to use.

This is somewhat inefficient, but provieded a quick work-around. 
Context-diffs to the files main.c and usrdb.c are included below.

--------- Context diff of main.c
--- main.c.ORG	Tue Jan 24 15:48:01 1995
+++ main.c	Tue Feb  7 19:32:10 1995
@@ -325,7 +325,7 @@
 		for (i = 0; i < sizeof ac.ac_comm && ac.ac_comm[i] != '\0';
 		    i++) {
 			char c = ac.ac_comm[i];
-
+printf("",c);
 			if (!isascii(c) || iscntrl(c)) {
 				ci.ci_comm[i] = '?';
 				ci.ci_flags |= CI_UNPRINTABLE;
@@ -397,19 +397,19 @@
 cmp_usrsys(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 	u_quad_t t1, t2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	t1 = c1->ci_utime + c1->ci_stime;
-	t2 = c2->ci_utime + c2->ci_stime;
+	t1 = c1.ci_utime + c1.ci_stime;
+	t2 = c2.ci_utime + c2.ci_stime;
 
 	if (t1 < t2)
 		return -1;
 	else if (t1 == t2)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
@@ -419,22 +419,22 @@
 cmp_avgusrsys(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 	double t1, t2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	t1 = c1->ci_utime + c1->ci_stime;
-	t1 /= (double) (c1->ci_calls ? c1->ci_calls : 1);
+	t1 = c1.ci_utime + c1.ci_stime;
+	t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
 
-	t2 = c2->ci_utime + c2->ci_stime;
-	t2 /= (double) (c2->ci_calls ? c2->ci_calls : 1);
+	t2 = c2.ci_utime + c2.ci_stime;
+	t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
 
 	if (t1 < t2)
 		return -1;
 	else if (t1 == t2)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
@@ -444,15 +444,15 @@
 cmp_dkio(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	if (c1->ci_io < c2->ci_io)
+	if (c1.ci_io < c2.ci_io)
 		return -1;
-	else if (c1->ci_io == c2->ci_io)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+	else if (c1.ci_io == c2.ci_io)
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
@@ -462,19 +462,19 @@
 cmp_avgdkio(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 	double n1, n2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	n1 = (double) c1->ci_io / (double) (c1->ci_calls ? c1->ci_calls : 1);
-	n2 = (double) c2->ci_io / (double) (c2->ci_calls ? c2->ci_calls : 1);
+	n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+	n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
 
 	if (n1 < n2)
 		return -1;
 	else if (n1 == n2)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
@@ -484,15 +484,15 @@
 cmp_cpumem(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	if (c1->ci_mem < c2->ci_mem)
+	if (c1.ci_mem < c2.ci_mem)
 		return -1;
-	else if (c1->ci_mem == c2->ci_mem)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+	else if (c1.ci_mem == c2.ci_mem)
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
@@ -502,23 +502,23 @@
 cmp_avgcpumem(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 	u_quad_t t1, t2;
 	double n1, n2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	t1 = c1->ci_utime + c1->ci_stime;
-	t2 = c2->ci_utime + c2->ci_stime;
+	t1 = c1.ci_utime + c1.ci_stime;
+	t2 = c2.ci_utime + c2.ci_stime;
 
-	n1 = (double) c1->ci_mem / (double) (t1 ? t1 : 1);
-	n2 = (double) c2->ci_mem / (double) (t2 ? t2 : 1);
+	n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
+	n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
 
 	if (n1 < n2)
 		return -1;
 	else if (n1 == n2)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
@@ -528,15 +528,15 @@
 cmp_calls(d1, d2)
 	const DBT *d1, *d2;
 {
-	struct cmdinfo *c1, *c2;
+	struct cmdinfo c1, c2;
 
-	c1 = (struct cmdinfo *) d1->data;
-	c2 = (struct cmdinfo *) d2->data;
+	memcpy(&c1,d1->data,sizeof(struct cmdinfo));
+	memcpy(&c2,d2->data,sizeof(struct cmdinfo));
 
-	if (c1->ci_calls < c2->ci_calls)
+	if (c1.ci_calls < c2.ci_calls)
 		return -1;
-	else if (c1->ci_calls == c2->ci_calls)
-		return (cmp_comm(c1->ci_comm, c2->ci_comm));
+	else if (c1.ci_calls == c2.ci_calls)
+		return (cmp_comm(c1.ci_comm, c2.ci_comm));
 	else
 		return 1;
 }
------------- End of main.c.diff

------------- Context diff of usrdb.c
--- usrdb.c.ORG	Thu Mar 24 19:42:01 1994
+++ usrdb.c	Wed Feb  8 17:14:33 1995
@@ -223,7 +223,7 @@
 usracct_print()
 {
 	DBT key, data;
-	struct userinfo *ui;
+	struct userinfo ui;
 	double t;
 	int rv;
 
@@ -232,29 +232,29 @@
 		warn("retrieving user accounting stats");
 
 	while (rv == 0) {
-		ui = (struct userinfo *) data.data;
+		memcpy(&ui,data.data,sizeof(ui));
 
 		printf("%-8s %9qu ",
-		    user_from_uid(ui->ui_uid, 0), ui->ui_calls);
+		    user_from_uid(ui.ui_uid, 0), ui.ui_calls);
 
-		t = (double) (ui->ui_utime + ui->ui_stime) /
+		t = (double) (ui.ui_utime + ui.ui_stime) /
 		    (double) AHZ;
 		if (t < 0.0001)		/* kill divide by zero */
 			t = 0.0001;
 
 		printf("%12.2lf%s ", t / 60.0, "cpu");
 
-		/* ui->ui_calls is always != 0 */
+		/* ui.ui_calls is always != 0 */
 		if (dflag)
-			printf("%12qu%s", ui->ui_io / ui->ui_calls, "avio");
+			printf("%12qu%s", ui.ui_io / ui.ui_calls, "avio");
 		else
-			printf("%12qu%s", ui->ui_io, "tio");
+			printf("%12qu%s", ui.ui_io, "tio");
 
 		/* t is always >= 0.0001; see above */
 		if (kflag)
-			printf("%12qu%s", ui->ui_mem / t, "k");
+			printf("%12qu%s", ui.ui_mem / t, "k");
 		else
-			printf("%12qu%s", ui->ui_mem, "k*sec");
+			printf("%12qu%s", ui.ui_mem, "k*sec");
 
 		printf("\n");
-------------- end of usrdb.c.diff 
	
>Audit-Trail:
>Unformatted: