[comp.unix.ultrix] auto-increment bug in Ultrix

khan@pslu1.psl.wisc.edu (Mumit Khan) (04/01/91)

 ---------------- MIPS C bug in post-increment of variables ----------
 MACHINE = DS3100
 OS = ULTRIX V4.1 (Rev. 52) System #1: Wed Dec 19 15:20:46 CST 1990
      UWS V4.1 (Rev. 197)

Note the output from the following program in various cases. MIPS C is 
the only one causing the problem (of not incrementing the global shared
variable "pc" in the call (*(*pc++))().

------------------------ START OF PROGRAM ---------------------------
#include <stdio.h>

typedef int (*Inst)();
#define StopInst (Inst) 0
static int dummy ();
static Inst machine[] = {dummy, dummy, dummy, dummy, dummy, StopInst};
static Inst *pc = NULL;

main () {
    extern int start;
    fprintf (stderr, "Starting pc: %x\n", pc = machine);
    for (; *pc != StopInst;)
	(*(*pc++)) ();		/* BUG BUG BUG BUG BUG BUG BUG */
}
static int dummy () {
    extern Inst *pc;
    fprintf (stderr, "PC (in dummy): %x\n", pc);
    return 0;
}


------------------------- END OF PROGRAM ------------------------

OUTPUT FROM MIPS CC. (Version 2.1)
> bug-mips-cc

Starting pc: 10000430
PC (in dummy): 10000430			<--- NOTE *NO* INCREMENT
PC (in dummy): 10000434
PC (in dummy): 10000438
PC (in dummy): 1000043c
PC (in dummy): 10000440
 

OUTPUT FROM MIPS GCC. (Version 2.1)
> gcc -v
gcc version 1.37.1 OSF 1.9.2.14 Ultrix Dec Mips Dec 29 1990
> bug-mips-gcc

Starting pc: 10000460
PC (in dummy): 10000464			<--- NOTE INCREMENT
PC (in dummy): 10000468
PC (in dummy): 1000046c
PC (in dummy): 10000470
PC (in dummy): 10000474


OUTPUT FROM SparcStation (IPC) CC. (SunOS rel. 4.1.1)
> bug-sun4-cc

Starting pc: 40a8
PC (in dummy): 40ac 			<--- NOTE INCREMENT
PC (in dummy): 40b0
PC (in dummy): 40b4
PC (in dummy): 40b8
PC (in dummy): 40bc

---------------------------------------------------------------------

D. Allen [CGL]) (04/15/91)

In article <1991Mar31.214127.5224@pslu1.psl.wisc.edu>, khan@pslu1.psl.wisc.edu (Mumit Khan) writes:
> 
>  ---------------- MIPS C bug in post-increment of variables ----------
>  MACHINE = DS3100
>  OS = ULTRIX V4.1 (Rev. 52) System #1: Wed Dec 19 15:20:46 CST 1990
>       UWS V4.1 (Rev. 197)
> 
> Note the output from the following program in various cases. MIPS C is 
> the only one causing the problem (of not incrementing the global shared
> variable "pc" in the call (*(*pc++))().

This is not a bug.  The C Language does not require the increment to
happen until the end of the expression, that is, until *after* the
function call.  Many compilers will do it *before* the function call,
but it is not required.

> ------------------------ START OF PROGRAM ---------------------------
> #include <stdio.h>
> 
> typedef int (*Inst)();
> #define StopInst (Inst) 0
> static int dummy ();
> static Inst machine[] = {dummy, dummy, dummy, dummy, dummy, StopInst};
> static Inst *pc = NULL;
> 
> main () {
>     extern int start;
>     fprintf (stderr, "Starting pc: %x\n", pc = machine);
>     for (; *pc != StopInst;)
> 	(*(*pc++)) ();		/* BUG BUG BUG BUG BUG BUG BUG */
> }
> static int dummy () {
>     extern Inst *pc;
>     fprintf (stderr, "PC (in dummy): %x\n", pc);
>     return 0;
> }
> 
> 
> ------------------------- END OF PROGRAM ------------------------
> 
> OUTPUT FROM MIPS CC. (Version 2.1)
> > bug-mips-cc
> 
> Starting pc: 10000430
> PC (in dummy): 10000430			<--- NOTE *NO* INCREMENT
> PC (in dummy): 10000434
> PC (in dummy): 10000438
> PC (in dummy): 1000043c
> PC (in dummy): 10000440
>  
> 
> OUTPUT FROM MIPS GCC. (Version 2.1)
> > gcc -v
> gcc version 1.37.1 OSF 1.9.2.14 Ultrix Dec Mips Dec 29 1990
> > bug-mips-gcc
> 
> Starting pc: 10000460
> PC (in dummy): 10000464			<--- NOTE INCREMENT
> PC (in dummy): 10000468
> PC (in dummy): 1000046c
> PC (in dummy): 10000470
> PC (in dummy): 10000474
> 
> 
> OUTPUT FROM SparcStation (IPC) CC. (SunOS rel. 4.1.1)
> > bug-sun4-cc
> 
> Starting pc: 40a8
> PC (in dummy): 40ac 			<--- NOTE INCREMENT
> PC (in dummy): 40b0
> PC (in dummy): 40b4
> PC (in dummy): 40b8
> PC (in dummy): 40bc
> 
> ---------------------------------------------------------------------

I quote from someone who read the ANSI book:

From: giguere@csg.uwaterloo.ca (Eric Giguere)
Subject: Re: Autoincrement in function calls; when?
Organization: University of Waterloo

In article <1991Apr9.143020.3504@watcgl.waterloo.edu> "Ian! D. Allen [CGL]" <idallen@watcgl.waterloo.edu> writes:
>Someone claims this is a bug, but I think it's just the way C works.
>
>>Newsgroups: comp.unix.ultrix
>>Subject: auto-increment bug in Ultrix(4.1) C (DS3100)
>>
>>Note the output from the following program in various cases. MIPS C is 
>>the only one causing the problem (of not incrementing the global shared
>>variable "pc" in the call (*(*pc++))().

Interesting problem.  Best to go straight to the horse's mouth on this
one, the ANSI Standard:                       

	Section 3.3.2.4:
        The side effect of updating the stored value of the operand
        shall occur between the previous and the next sequence point.

Hmmm... so what's a sequence point?

	Section 2.1.2.3:
        At certain specified points in the execution sequence called
        sequence points, all side effects of previous evaluations shall
        be complete and no side effects of subsequent evaluations shall
        have taken place.

    Section 3.6:
        The end of a full expression is a sequence point.

    Section 3.3:
        Between the previous and next sequence point an object shall
        have its stored value modified at most once by the evaluation
        of an expression.

So what can we conclude?  Only that the increment has to have taken effect
by the end of the expression.  Hence within the function call

                (*(*pc++))()

the value of pc is implementation-defined.  Congratulations, Ian!, you
can pick up your prize at....

-- 
Eric Giguere                                       giguere@csg.UWaterloo.CA
           Unlike the cleaning lady, I have to do Windows.
-- 
-IAN! (Ian! D. Allen) idallen@watcgl.uwaterloo.ca idallen@watcgl.waterloo.edu
 [129.97.128.64]  Computer Graphics Lab/University of Waterloo/Ontario/Canada

merritt@milton.u.washington.edu (Ethan Merritt) (04/16/91)

In article <1991Apr15.161123.16353@watcgl.waterloo.edu>  idallen@watcgl.waterloo.edu (Ian! D. Allen [CGL]) writes (quoting others):

>  [ discussion of why failing to increment pc in the expression below before
>    completing function call is "not a bug" ]
>  So what can we conclude?  Only that the increment has to have taken effect
>  by the end of the expression.  Hence within the function call
>  
>                  (*(*pc++))()
>  
>  the value of pc is implementation-defined.  Congratulations, Ian!, you
>  can pick up your prize at....
>  
	All right, I'm willing to play the straight man here.  What is
the ANSI-provided definition of "expression"?  As I see it the lexical element
(*pc++) is already an expression, and the original complaint is perfectly
valid.  To make the point clearer, what would your ruling be on a statement
of the form:
		extern (void *)xxx;
		...
		(*(xxx = *pc++))();

What do you conclude about the value of xxx during the execution of the
function invoked?
						Ethan A Merritt
--------------------------------------------------------------------
Dept of Biological Structure                H510 Health Sciences
University of Washington SM-20              (206)543-8865
Seattle, WA 98195                           merritt@u.washington.edu
--------------------------------------------------------------------

diamond@jit345.swstokyo.dec.com (Norman Diamond) (04/16/91)

In article <1991Apr15.161123.16353@watcgl.waterloo.edu> idallen@watcgl.waterloo.edu (Ian! D. Allen [CGL]) writes:
>In article <1991Mar31.214127.5224@pslu1.psl.wisc.edu>, khan@pslu1.psl.wisc.edu (Mumit Khan) writes:
>> Note the output from the following program in various cases. MIPS C is 
>> the only one causing the problem (of not incrementing the global shared
>> variable "pc" in the call (*(*pc++))().
[...]
>> typedef int (*Inst)();
>> static Inst *pc = NULL;
>> 	(*(*pc++)) ();		/* BUG BUG BUG BUG BUG BUG BUG */

>This is not a bug.

Well, Mumit Khan is using a compiler that does not claim ANSI conformance,
and complaining that the result is not ANSI conformant.  This makes the
complaint partly meaningless.

(However, quality of implementation might possibly be a consideration even
for non-conformant compilers.  Disclaimer:  Although I do not know if this
is possible or not, my employer is not the one suggesting it.)

For an ANSI-conformant compiler, it would indeed be a bug.

>The C Language does not require the increment to happen until the end of
>the expression, that is, until *after* the function call.
>I quote from someone who read the ANSI book:
>From: giguere@csg.uwaterloo.ca (Eric Giguere)
>	Section 3.3.2.4:
>        The side effect of updating the stored value of the operand
>        shall occur between the previous and the next sequence point.
>	Section 2.1.2.3:
>        At certain specified points in the execution sequence called
>        sequence points, all side effects of previous evaluations shall
>        be complete and no side effects of subsequent evaluations shall
>        have taken place.
>    Section 3.6:
>        The end of a full expression is a sequence point.
>    Section 3.3:
>        Between the previous and next sequence point an object shall
>        have its stored value modified at most once by the evaluation
>        of an expression.
>So what can we conclude?  Only that the increment has to have taken effect
>by the end of the expression.
>Congratulations, Ian!, you can pick up your prize at....

Messrs. !Allen and Giguere win booby prizes on this one.
There are also sequence points at some other places, too.  For example:
     Section 3.3.2.2, page 42, line 21:
         ... but there is a sequence point before the actual call.

If the compiler in this case had claimed ANSI conformance, then its
implementors would also deserve booby prizes.  (Disclaimer:  this is 
not my employer's opinion.)
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

lhoe@iddth.id.dk (Lasse H Oestergaard (EMP)) (04/23/91)

diamond@jit345.swstokyo.dec.com (Norman Diamond) writes:

>In article <1991Apr15.161123.16353@watcgl.waterloo.edu> idallen@watcgl.waterloo.edu (Ian! D. Allen [CGL]) writes:
>>In article <1991Mar31.214127.5224@pslu1.psl.wisc.edu>, khan@pslu1.psl.wisc.edu (Mumit Khan) writes:
>>> Note the output from the following program in various cases. MIPS C is 
>>> the only one causing the problem (of not incrementing the global shared
>>> variable "pc" in the call (*(*pc++))().
>[...]
>>> typedef int (*Inst)();
>>> static Inst *pc = NULL;
>>> 	(*(*pc++)) ();		/* BUG BUG BUG BUG BUG BUG BUG */

>>This is not a bug.

>Well, Mumit Khan is using a compiler that does not claim ANSI conformance,
>and complaining that the result is not ANSI conformant.  This makes the
>complaint partly meaningless.

>(However, quality of implementation might possibly be a consideration even
>for non-conformant compilers.  Disclaimer:  Although I do not know if this
>is possible or not, my employer is not the one suggesting it.)

>For an ANSI-conformant compiler, it would indeed be a bug.

>>The C Language does not require the increment to happen until the end of
>>the expression, that is, until *after* the function call.
>>I quote from someone who read the ANSI book:
>>From: giguere@csg.uwaterloo.ca (Eric Giguere)
>>	Section 3.3.2.4:
>>        The side effect of updating the stored value of the operand
>>        shall occur between the previous and the next sequence point.
>>	Section 2.1.2.3:
>>        At certain specified points in the execution sequence called
>>        sequence points, all side effects of previous evaluations shall
>>        be complete and no side effects of subsequent evaluations shall
>>        have taken place.
>>    Section 3.6:
>>        The end of a full expression is a sequence point.
>>    Section 3.3:
>>        Between the previous and next sequence point an object shall
>>        have its stored value modified at most once by the evaluation
>>        of an expression.
>>So what can we conclude?  Only that the increment has to have taken effect
>>by the end of the expression.
>>Congratulations, Ian!, you can pick up your prize at....

>Messrs. !Allen and Giguere win booby prizes on this one.
>There are also sequence points at some other places, too.  For example:
>     Section 3.3.2.2, page 42, line 21:
>         ... but there is a sequence point before the actual call.

>If the compiler in this case had claimed ANSI conformance, then its
>implementors would also deserve booby prizes.  (Disclaimer:  this is 
>not my employer's opinion.)
>--
>Norman Diamond       diamond@tkov50.enet.dec.com
>If this were the company's opinion, I wouldn't be allowed to post it.

  Try looking at the INDEX in the standard. That will, in addition to the
abovementioned references, point you to  APPENDIX A.2, which states
(quoted in full, since people don't seem to know this, very important,
 definition):

    The following is the sequence points described in paragraph 2.1.2.3.

    . The call to a function, after the arguments have been evaluated
      (paragraph 3.3.2.2)

    . The end of the first operand of the following operators:
      logical AND  &&  (paragraph 3.3.13); logical OR  ||  (paragraph
      3.3.14); conditional ?  (paragraph 3.3.15); comma , (paragraph
      3.3.17).

    . The end of a full expression: An initializer (paragraph 3.5.7);
      the expression in an expression statement (paragraph 3.6.3);
      the controlling expression of a selection statement (if  or
      switch) (paragraph 3.6.4); the controlling expression of a  while
      or  do  statement (paragraph 3.6.5); each of the 3 expressions of
      a  for  statement (paragraph 3.6.5.3); the expression in a
       return  statement (paragraph 3.6.6.4).

End of quote.

Now, together with paragraph 2.1.2.3 (see included articles), the first of 
the above rules quite clearly requires a compliant compiler to do the
increment BEFORE the call.
  That seems more important than handing out wisecracks and booby prizes.
  Unfortunately KERNIGHAN and RITCHIE (even in the 2.d, so called ANSI,
compliant !? edition) mostly ignores this problem, which possibly is the 
cause of the misstatements seen in the previous articles.

Lasse H. Oestergaard          lhoe@id.dth.dk