aliasing problem with va_arg

Mark Mitchell mark@markmitchell.com
Tue Oct 27 03:02:00 GMT 1998


    Mark> 	How hard would fixing the macros be?  Would you mind
    Mark> sending me the preprocessed sun-solaris2 source for your
    Mark> example, so that I could look at it with a cross-compiler?

    Jim> I didn't even think of fixing va-sparc.h.  I just assumed it
    Jim> couldn't be.  It is possible that we might be able to do
    Jim> something there.

I think I've figured out how to fix the SPARC macros, at least.  To be
ANSI/ISO-compliant, without compiler magic (like
__builtin_va_arg_incr, etc.), the macros must not access the storage
except by access through pointers of type `char*' or of the type
actually there.  So, it's easy to see what's going wrong in the SPARC
macros:

    ? ({ union {char __d[sizeof (TYPE)]; int __i[2];} __u;	\
	 __u.__i[0] = ((int *) (void *) (pvar))[0];		\
	 __u.__i[1] = ((int *) (void *) (pvar))[1];		\
	 (pvar) = (char *)(pvar) + 8;				\
	 (TYPE *) (void *) __u.__d; })				\

tries to treat `pvar' as an `int*', and indirect through it.  Thus,
the storage at `((int*) pvar)[0]' and `((int*) pvar)[1]' is treated
both as an `int' (here) and as a `double' by the client code.  But,
all this code is trying to do is treat `pvar' as a pointer to an
8-byte type.  So, why not just write:

  ((pvar) = (char*) (pvar) + 8,
   (TYPE*) (void*) ((char*) (pvar) - 8))

which is type-correct?  I think this fixes the bug, but my SPARC
assembler is rusty.  Here's the generated code for your test case:

  #include <stdarg.h>

  extern double bar (double);

  double foo (va_list ap) {
    double d = va_arg (ap, double);
    return bar (d);
  }

gets:

  foo:
	  !#PROLOGUE# 0
	  save	%sp, -112, %sp
	  !#PROLOGUE# 1
	  call	bar, 0
	  ldd	[%i0], %o0
	  ret
	  restore

instead of the (bogus):

  foo:
	  !#PROLOGUE# 0
	  save	%sp, -120, %sp
	  !#PROLOGUE# 1
	  ld	[%i0+4], %o2
	  ld	[%i0], %o3
	  st	%o2, [%fp-20]
	  ldd	[%fp-24], %o0
	  call	bar, 0
	  st	%o3, [%fp-24]
	  ret
	  restore

Note that the second version (besides being incorrect) is vastly
inferior; it dumps the arguments into the stack before loading them
back into %o0,%o01 while with my proposed change the redundant
loads/stores are eliminated.  The SH port is the other port that seems
to use this `union' trickery.  I didn't look at those macros at all.

Does this analysis seem right to you?  If so, I suggest you modify
va-sparc.h accordingly.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com



More information about the Gcc mailing list