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