Bug 27153

Summary: function result is dereferenced error
Product: gcc Reporter: Alexey Smirnov <alexey>
Component: cAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: major CC: alexey, algorithmus, asokumar, av1474, bala, barnarr, behloul.younes, bmead15, buergel, carpman, chuchunxin, devnull, d_picco, eric.mcvicker, fuchsia.groan, gaurav_har, gcc-bugs, gcc, ggs, jandres, janis, jompo, krs, lid, lindahlb, lxg8906, mayer, mikaldaz, nakkore, nobs, pierre.van.de.laar_at_philips.com, qyang, ramiller, raoulgough, rglan, rjvbertin, robc, s9322036, SimonX200, smartmouse714, suan, super.aorta, svetozarmarkov, tczarnecki, vanveghel, vitaly, zshao
Priority: P3    
Version: 3.4.6   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:

Description Alexey Smirnov 2006-04-14 02:28:19 UTC
An error occurs when a function result is dereferenced if used as another function's argument:

void *func(int num) {
  static int val;

  val=num;
  return (void*)&val;
}

int main() {
  printf("%d %d %d\n", *((int*)func(1)), *((int*)func(2)), *((int*)func(3)));
  return 0;
}

Output is "1 1 1" instead of "1 2 3". Compiled using "gcc test.c -o test".
Comment 1 Andrew Pinski 2006-04-14 02:31:59 UTC
It is undefined on which function call is done in what order and also were the dereferencing is done, before or after the next function call.

*** This bug has been marked as a duplicate of 11751 ***
Comment 2 Alexey Smirnov 2006-04-14 02:46:35 UTC
> It is undefined on which function call is done in what order

It does not matter in this example.

> and also were the
> dereferencing is done, before or after the next function call.

It does not matter either. The evaluation of a function argument is an atomic procedure. If it starts it should generate a result. Isn't it strange if the compiler evaluates a little bit of the first argument, then a little bit of the second argument, then a little bit of the third argument, then goes back to the first and completes the evaluation?
Comment 3 Andrew Pinski 2006-04-14 02:50:56 UTC
(In reply to comment #2)
> > It is undefined on which function call is done in what order
> 
> It does not matter in this example.
> 

Why do you think that?

It does generate a call to func but not as you expected it.

Anyways the way GCC is compiling your code is the following which is valid under the standard:

int *a, *b, *c;
c = func(3);
b = func(2);
a = func(1);

  printf("%d %d %d\n", *(a), *(b), *(c));

so the order is still undefined as there is no sequence point between the function calls.




*** This bug has been marked as a duplicate of 11751 ***
Comment 4 Andrew Pinski 2006-04-14 02:55:30 UTC
(In reply to comment #2)
> It does not matter either. The evaluation of a function argument is an atomic
> procedure. If it starts it should generate a result. Isn't it strange if the
> compiler evaluates a little bit of the first argument, then a little bit of the
> second argument, then a little bit of the third argument, then goes back to the
> first and completes the evaluation?

Why do you think it is an atomic procedure?  There is nothing in the standard that says:

f(a, a++, b+(a++)+(a++))

evaluates each of those as atomic in fact the reverse is true in that it says the order is undefined as there is no sequence point inbetween those arguments as the comma in this case is not the comma operator but argument seperator.
Comment 5 Alexey Smirnov 2006-04-14 03:06:51 UTC
> > > It is undefined on which function call is done in what order
> > It does not matter in this example.
> Why do you think that?

Because the result is "x x x" for all orders instead of 1 2 3.

> int *a, *b, *c;
> c = func(3);
> b = func(2);
> a = func(1);
> 
>   printf("%d %d %d\n", *(a), *(b), *(c));

I understand and disagree that this is not a bug. Consider the following example:

char *arr;
void read_input() {
  arr=malloc(10);
  read(fd, arr, 10);
}

void print_input() {
  if (!arr) printf ("input empty\n"); else 
  {   printf("%s\n", arr); free(arr); arr=NULL; }
}

go(read_input, print_input);

If the compiler "optimizes" go() call so that the first argument is not evaluated completely then evaluates the second argument and finally completes evaluation of the first argument after arr was freed, then it is a segfault. However, the function is evaluated correctly if the arguments are evaluated completely.
Comment 6 Andrew Pinski 2006-04-14 16:54:07 UTC
In C, there is no ordering left to right, please go read the C FAQ at:
http://www.eskimo.com/~scs/c-faq.com/expr/index.html
subpage:
http://www.eskimo.com/~scs/c-faq.com/expr/comma.html

This page answers your question of this being undefined and this is not a bug in GCC.

*** This bug has been marked as a duplicate of 11751 ***
Comment 7 Alexey Smirnov 2006-04-18 00:06:43 UTC
(In reply to comment #6)
> In C, there is no ordering left to right, please go read the C FAQ at:
> http://www.eskimo.com/~scs/c-faq.com/expr/index.html
> subpage:
> http://www.eskimo.com/~scs/c-faq.com/expr/comma.html

The problem has nothing to do with ordering. It is in because arguments are evaluated not completely before the next one is evaluated. 
Comment 8 Andrew Pinski 2006-04-18 00:21:30 UTC
(In reply to comment #7)
> (In reply to comment #6)
> > In C, there is no ordering left to right, please go read the C FAQ at:
> > http://www.eskimo.com/~scs/c-faq.com/expr/index.html
> > subpage:
> > http://www.eskimo.com/~scs/c-faq.com/expr/comma.html
> The problem has nothing to do with ordering. It is in because arguments are
> evaluated not completely before the next one is evaluated. 

Even then, the order inside the epxressions is not specified which means a+b+c+d can be such that the a, b, c, and d subexpressions are in any order as long as there are not squence points, even then it is only the a partial ordering.


For an example:

(a, b) + (c, d) + (e, f)
can be evaulated in the following order and would be still be valid:

a c e b d f add add
or

a b c e d f add add

as long as the ordering of a comes before b and c comes before d and e comes before f, it is valid.  This is what is meant by partial ordering.

therefor in your orginal expample we have:

f ("", OP0(f0()), OP1(f1()), OP2(f2()));

the ordering here of each sub expression is not specified in that
f0() might come before f2() but it does have to come before the call to f and the operation OP0 just because of dependicies.

Hopefully this explains what is going on here and why this bug is invalid and is a dup of PR 11751.

What you need to think of is that the comma in a function call is just a seperator and there is no evaulation requirement on which expression (or subexpression) gets evaulated first in the same way:

(a++ + b++) + (a++ + b++);

there is no requirment which a++ (or b++) is evaulated first.
Comment 9 Wolfgang Bangerth 2006-04-18 03:21:22 UTC
> It does not matter either. The evaluation of a function argument is an atomic
> procedure.

No, it actually isn't.


> If it starts it should generate a result. Isn't it strange if the
> compiler evaluates a little bit of the first argument, then a little bit of the
> second argument, then a little bit of the third argument, then goes back to the
> first and completes the evaluation?

Maybe. But it's allowed under the standard, and if the compiler can produce
better code this way it should use its liberty.

W.
Comment 10 Falk Hueffner 2006-04-18 06:27:41 UTC
Uhm, this has nothing to do at all with evaluation order. Evaluation
order of arguments is unspecified (not undefined, which wouldn't make a
lot of sense), but that is in fact irrelevant here, it could lead to,
say, 3 1 2, but not 1 1 1.

The actual problem is that val is modified more than once without an 
intervening sequence point, which makes the behavior undefined.
Comment 11 joseph@codesourcery.com 2006-04-18 11:17:33 UTC
Subject: Re:  function result is dereferenced error

On Tue, 18 Apr 2006, falk at debian dot org wrote:

> Uhm, this has nothing to do at all with evaluation order. Evaluation
> order of arguments is unspecified (not undefined, which wouldn't make a
> lot of sense), but that is in fact irrelevant here, it could lead to,
> say, 3 1 2, but not 1 1 1.
> 
> The actual problem is that val is modified more than once without an 
> intervening sequence point, which makes the behavior undefined.

No, this testcase is unspecified, not undefined.  There are intervening 
sequence points at the start and end of each call to function, and 
function calls do not overlap (DR#087); each call to func suspends the 
execution of main until func returns.  However, the evaluation of the 
arguments to printf may overlap and the order is unspecified, so there are 
many possible outputs from the program (but "3 2 1" and "3 1 1", for 
example, are not possible).

Comment 12 Falk Hueffner 2006-04-18 12:37:41 UTC
(In reply to comment #11)
> No, this testcase is unspecified, not undefined.  There are intervening 
> sequence points at the start and end of each call to function

OK.

> However, the evaluation of the 
> arguments to printf may overlap and the order is unspecified, so there are 
> many possible outputs from the program (but "3 2 1" and "3 1 1", for 
> example, are not possible).

I don't understand why is "3 2 1" is not possible. How about "1 1 1"? Is
this a bug in gcc after all?

Comment 13 joseph@codesourcery.com 2006-04-18 12:57:37 UTC
Subject: Re:  function result is dereferenced error

On Tue, 18 Apr 2006, falk at debian dot org wrote:

> > However, the evaluation of the 
> > arguments to printf may overlap and the order is unspecified, so there are 
> > many possible outputs from the program (but "3 2 1" and "3 1 1", for 
> > example, are not possible).
> 
> I don't understand why is "3 2 1" is not possible. How about "1 1 1"? Is
> this a bug in gcc after all?

"1 1 1" is possible: first evaluate func(3), then func(2), then func(1), 
then do all the dereferences.

To get "3 2 1", the initial "3" requires func(3) to be evaluated between 
the evaluation of func(1) and its dereference, so func(3) is evaluated 
after func(1); but likewise the final "1" requires func(1) to be evaluated 
after func(3).