[comp.sys.sun] unions as function arguments

stevec@lccr.cs.sfu.ca (Steve Cumming) (03/04/89)

A lot of applications have constructions that look like this: 

typedef union {
	int a;
	char *b;
	struct c *d;
	float e;
} foo;

main(){

	foo c;
	init(0,0);	/* initialise the head of
			   an attribute list */
	.
	.
	.
}
init(a,b)
int a;
foo b;
{
	if (a == 0 && b.a == 0){
		 /* init some tables and return*/
		 return;
	}

	return;
}

This produces unpleasant results on Sun4's under SunOS4 and SunOS4.01.
Usually segmentation faults in the case of calls like the call to init,
above. The symptoms vary with the exact contents of the union. But
compiling with -misalign does not make them go away in all cases.

Programmes like pic and Unipress emacs are riddled with calls of this
sort.

What I want to know is, is it legal to pass a union to a function?
Reasonably careful examination of K&R (both editions) makes me think that
it is. Am I right?  The fact tha Famous (tm) People wrote some of the code
in question also makes me thinks so. 

In that case passing a constant 0 as a union should cause the compiler to
do the obvious thing.  It don't. 

Can anyone state authoritatively whether such constructions should work or
not?

Here is another, slightly different, example, which reliably  causes a Sun
4 to crash: 


main()
	char *a = "a";
			/* call _DefMac,1 with
			   %o0 pointing at "a"
			*/
	DefMac(a);
	exit;
}

DefMac(body)
union { 
    char * b_name;
    char * b_string;
} body;

{ 
	char * foo = body.b_string; /* ld [%i0],%o0 
				       st [%o0],[%fp+-0x4]
			 	       ld [%fp+-0x4],%o1 
				    */
	a = *foo; /*dies here on:      ldsb [%o1],%01 */ 
	return;
}

The attempt to dereference foo seems to tickle the infamous Sun4 watchdog
reset bug. Again, compiling with -misalign does not fix the problem,
although it yields more verbose code.

I do not have access to enough data on SPARC to make sense out of the .s
code - the effect is that of an extra level of dereferencing, but it all
looks OK to me. Sun has <not> fixed this is 4.01.

Steve Cumming	stevec@lccr.cs.sfu.ca	{uunet|...}!ubc-cs!fornax!stevec
School of CS
SFU		(604) 291-4399	        ... I'll be far off and gone
Vancouver, CDN					like summer wages.

[[ But it's not all okay.  In the second example, "main" passes a "char *"
to a function that expects a union.  This is clearly wrong.  In the first
case, I believe that "0" is not sufficient.  To be safe, one should set
one member of a dummy union to 0 and pass that in.  In general, I believe
that passing and returning unions is legal (just liek it is with
structures) , but calling a function with something it isn't expecting is
never legal.  --wnl ]]

mikel@teraida.UUCP (Mikel Lechner) (03/21/89)

In article <892@fornax.UUCP> stevec@lccr.cs.sfu.ca (Steve Cumming) writes:
> What I want to know is, is it legal to pass a union to a function?

Yes, just like it is legal to pass a structure to a function.

> In that case passing a constant 0 as a union should cause the compiler to
> do the obvious thing.  It don't. 

No.  Passing an integer argument and passing a union containing an integer
are not the same thing.  This works on most systems because the union and
integer are aligned the same, passed the same way, and are the same size.
However, this is not strictly correct C.  I ran into exactly this same
problem with some code I inherited, when first porting to the Sun4.

Sun took the liberty with the Sun4 to pass structs and unions differently
from scalar arguments.  The register window architecture of the SPARC is
used to pass scalar arguments through registers.  Non-scalar arguments are
passed on the stack the old-fashioned way.  If you pass an int to a
function expecting a union.  The caller puts the argument on the stack,
and the receiving fuction looks for it on the stack.  And the program
usually gets a segmentation violation.

Mikel Lechner			decwrl!teraida!mikel
Teradyne EDA			(408) 980-5200
5155 Old Ironsides Drive
Santa Clara, Ca 95054

[[ Isn't that what I said?  --wnl ]]