This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Re: Re[2]: gcc 2.95.2 problem: alloca done within argument list evaluation, corrupts the rest of the argument list
- To: Alexandre Oliva <oliva at lsd dot ic dot unicamp dot br>
- Subject: Re: Re[2]: gcc 2.95.2 problem: alloca done within argument list evaluation, corrupts the rest of the argument list
- From: Jeffrey A Law <law at cygnus dot com>
- Date: Fri, 14 Jan 2000 05:02:37 -0700
- cc: etienne dot lorrain at ibm dot net, gcc-bugs at gcc dot gnu dot org
- Reply-To: law at cygnus dot com
In message <or3ds0yk2s.fsf@garnize.lsd.ic.unicamp.br>you write:
> On Jan 14, 2000, Etienne LORRAIN <etienne_lorrain@yahoo.fr> wrote:
>
> >> >> f (yyy((t1 = alloca(ALLOCA_SIZE),xxx(t1))), 2);
> >> ^ matches ^
> >> > undefined behavior: t1 is used and changed without
> >> > resynchronisation point in between.
> >> But there is a sequence point. t1=alloca(...) and xxx(t1) are
> >> arguments or a function call, they form a single expression by means
> >> of the comma operator.
>
> oops, I meant they are *not* arguments to a function call.
Note, anytime you use alloca, you're actually in the realm of unspecified
behavior. alloca is evil for numerous reasons. Use it at your
own risk (IMHO), particularly when you use it within an argument list.
> > Was true for the 8 (really different) processor I used at work...
> > In fact I do not know a real implementation of C without a stack,
> > or how to implement varargs without a stack and pushing params
> > right to left.
>
> Any architecture that doesn't provide a fast push instruction doesn't
> often lead to right-to-left evaluation of arguments. Moreover, most
> RISC architectures use registers to pass (some) arguments, so the
> order of evaluation of arguments just doesn't matter.
Actually it does matter, even on risc machines that use registers for
parameter passing.
A typical trait of ABIs that pass arguments in registers is to still
allocate stack space for such arguments (it makes implementing varargs
and stdarg much easier).
That stack space is considered a property of the *called* routine, just
like a call clobbered register. ie a called routine can stomp all over
that area in any way it desires.
It is also typical for ABIs that pass arguments in registers to sometimes
need to construct an argument on the stack, then promote it into an
argument register.
So consider
killme (a, frobnitz (), a)
Where "a" has to be constructed on the stack (pretend it's a 3 byte
structure or something like that ;-). We'll likely construct one or
both instances of "a" into their stack slots, then perform the call to
frobnitz which may clobber those stackslots. Opps. So we have to
have code to either change the order of evaluation or save off stack
slots where we've placed things. GCC takes the second approach.
(Principle of least surprise -- most folks don't expect the compiler to
potentially evaluate arguments in the wrong order, even if technically
it can). Saving off the stack slots is also easier :-)
> And, even when
> the arguments won't fit in the registers used for this purpose, and
> they have to be passed in the stack, on most RISC architectures you'll
> get the stack space pre-allocated for all arguments before any of them
> is evaluated, and then, they're evaluated in any order and stored in
> the appropriate places in the stack.
Yes, but the fact that they're stuffed into the stack means we've got the
same kind of problem. Consider the following; pretend everything is
just an integer (including the return values), but we can only pass one
parameter in a register.
blah (oof (x, y), b, c, zap (p, q));
We have to be careful about order of evaluation here too and deal with the
same issues noted above since the callee is generally allowed to modify stack
slots for arguments that were passed in.
jeff