Does this cause undefined behaviour?

Discussion in 'C Programming' started by ozbear, Dec 30, 2003.

  1. ozbear

    ozbear Guest

    Someone was asking in another forum how to translate:
    if (x && (y1=(y+y1)/2)) /* all integers with defined values */
    to another language.

    I am at odds with myself as to whether this causes undefined behaviour

    in the first place. Does the subexpression (y1=(y+y1)/2)
    cause UB because /y/ is both modified and used without an
    intervening sequence point attached to the larger expression
    or is it ok because the value of the assignment is the left
    hand side is used?

    In otherwords, the simple statement:

    y = (y+y1)/2;

    is well defined assuming reasonable values for y and y1 but when
    used in a larger expression as above does it become UB since
    /y/ is now both modified and used?

    Or, is it ok since /y/ isn't actually used in the larger
    expression but the well-defined value assigned to it?

    My question would equally apply, I think, to something like...

    x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

    Regards, Oz
     
    ozbear, Dec 30, 2003
    #1
    1. Advertising

  2. ozbear <> scribbled the following:
    > Someone was asking in another forum how to translate:
    > if (x && (y1=(y+y1)/2)) /* all integers with defined values */
    > to another language.


    > I am at odds with myself as to whether this causes undefined behaviour


    > in the first place. Does the subexpression (y1=(y+y1)/2)
    > cause UB because /y/ is both modified and used without an
    > intervening sequence point attached to the larger expression
    > or is it ok because the value of the assignment is the left
    > hand side is used?


    ITYM /y1/, not /y/, there.

    > In otherwords, the simple statement:


    > y = (y+y1)/2;


    > is well defined assuming reasonable values for y and y1 but when
    > used in a larger expression as above does it become UB since
    > /y/ is now both modified and used?


    No, I don't think it becomes UB, unless your larger expression
    modifies or uses /y1/ (again, ITYM that) in a different place.

    > Or, is it ok since /y/ isn't actually used in the larger
    > expression but the well-defined value assigned to it?


    Yes, I think that's the case.

    > My question would equally apply, I think, to something like...


    > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */


    It's a good analogy. That expression is, AFAIK, completely safe.
    What would cause UB would be y = y = (y+y2)/2, modifying y twice
    without intervening sequence points, but your expression above
    doesn't do that.

    --
    /-- Joona Palaste () ------------- Finland --------\
    \-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
     
    Joona I Palaste, Dec 30, 2003
    #2
    1. Advertising

  3. ozbear

    Ben Pfaff Guest

    (ozbear) writes:

    > Someone was asking in another forum how to translate:
    > if (x && (y1=(y+y1)/2)) /* all integers with defined values */
    > to another language.
    >
    > I am at odds with myself as to whether this causes undefined behaviour
    > in the first place. Does the subexpression (y1=(y+y1)/2)
    > cause UB because /y/ is both modified and used without an
    > intervening sequence point attached to the larger expression
    > or is it ok because the value of the assignment is the left
    > hand side is used?


    No, this subexpression is well-defined, for the same reason that
    `x = x + 1' is well-defined.

    > In otherwords, the simple statement:
    >
    > y = (y+y1)/2;
    >
    > is well defined assuming reasonable values for y and y1 but when
    > used in a larger expression as above does it become UB since
    > /y/ is now both modified and used?


    Not in this case: y (and y1) aren't mentioned in the larger
    expression other than in that subexpression. Furthermore, there
    is a sequence point between the left and right side of &&.

    --
    int main(void){char p[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.\
    \n",*q="kl BIcNBFr.NKEzjwCIxNJC";int i=sizeof p/2;char *strchr();int putchar(\
    );while(*q){i+=strchr(p,*q++)-p;if(i>=(int)sizeof p)i-=sizeof p-1;putchar(p\
    );}return 0;}
     
    Ben Pfaff, Dec 30, 2003
    #3
  4. Joona I Palaste wrote:

    > ozbear <> scribbled the following:
    >
    >> x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

    >
    >
    > It's a good analogy. That expression is, AFAIK, completely safe.
    > What would cause UB would be y = y = (y+y2)/2, modifying y twice
    > without intervening sequence points, but your expression above
    > doesn't do that.
    >


    Undefined behavior also results from /using/ the value of an object (for
    some purpose other than determining its new value) and also modifying it
    without an intervening sequence point. But in this case, the object is
    only used for determining the new value.

    So this is obviously undefined because it modifies i twice:

    i = a[i++];

    but this is also undefined, even though it does not modify anything
    multiple times:

    a[i++] = i;

    -Kevin
    --
    My email address is valid, but changes periodically.
    To contact me please use the address from a recent posting.
     
    Kevin Goodsell, Dec 30, 2003
    #4
  5. (ozbear) writes:

    > Does the subexpression (y1=(y+y1)/2) cause UB because /y/ is both
    > modified and used without an intervening sequence point


    It is not necessarily undefined behavior to modify an object and use its
    value without intervening sequence point. Essentially, there are two rules
    (with respect to the modification of objects) about what is allowed
    between two sequence points:

    (1) The value of the object may be modified at most once.
    (2) If the value of the object is modified at all, the previous value
    may be used only to determine the new value.

    The standard gives two examples of undefined behavior:

    i = ++i + 1; violates (1), because the value of `i' is modified
    twice.
    a[i++] = i; violates (2). While `i' is modified only once, its
    previous value is used to determine its storage
    location (as opposed to its new value).

    Martin
     
    Martin Dickopp, Dec 30, 2003
    #5
  6. On Tue, 30 Dec 2003 21:59:29 GMT, (ozbear) wrote:

    > In otherwords, the simple statement:
    >
    > y = (y+y1)/2;
    >
    > is well defined assuming reasonable values for y and y1 but when
    > used in a larger expression as above does it become UB since
    > /y/ is now both modified and used?


    No. The behaviour of an expression which is modifying an object and
    using the value of this object without intervening sequence point
    would only be undefined if a serial execution of the read and write
    accesses to the object could possibly occur either in the order
    read(y)->write(y) _or_ in the order write(y)->read(y). In this case
    the read access to y _must_ occur before the write access because the
    old value of y is needed to determine the new value stored to y.

    The behaviour of the expression /*X*/ in

    int x,y=0;

    x = y + (y=3) /*X*/;

    is undefined because read|write could occur in either order. Note that
    the reason for undefinedness is not primarily the fact that -
    depending on the order of evaluation of the subexpressions - the
    result could be either 0+3=3 or 3+3=6 but the bare fact that the read
    access to y for <y> might occur before or after the write access to y
    for <y=3>.

    --
    Horst
     
    Horst Kraemer, Dec 31, 2003
    #6
  7. ozbear

    Richard Bos Guest

    (ozbear) wrote:

    > My question would equally apply, I think, to something like...
    >
    > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */


    An additional point: it may seem that this causes undefined behaviour,
    because

    - a new value is computed for y (involving y, but that part is OK);
    - the value of y is then assigned to x, without an intervening
    sequence point.

    However, this is not what happens. _This_ is:

    - a new value is computed for y (involving the old y in an OK manner);
    - that same _value_ is also the value of the assignment _expression_,
    which is then assigned to x.

    IOW, the evaluation of the inner assignment expression does not, in the
    abstract machine, read y again; it evaluates its right hand side, and
    then _both_ assigns this to y _and_ passes it on to the outer
    assignment.

    Richard
     
    Richard Bos, Dec 31, 2003
    #7
  8. (Richard Bos) writes:

    > (ozbear) wrote:
    >
    > > My question would equally apply, I think, to something like...
    > >
    > > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

    >
    > An additional point: it may seem that this causes undefined behaviour,
    > because
    >
    > - a new value is computed for y (involving y, but that part is OK);
    > - the value of y is then assigned to x, without an intervening
    > sequence point.
    >
    > However, this is not what happens.


    Even if it does, it's not UB according to 6.5#2. It's not forbitten to
    modify two distinct objects without intervening sequence point, only to
    modify the same object more than once.

    > _This_ is:
    >
    > - a new value is computed for y (involving the old y in an OK manner);
    > - that same _value_ is also the value of the assignment _expression_,
    > which is then assigned to x.
    >
    > IOW, the evaluation of the inner assignment expression does not, in the
    > abstract machine, read y again; it evaluates its right hand side, and
    > then _both_ assigns this to y _and_ passes it on to the outer
    > assignment.


    Does the standard really guarantee that `y' is only read once in the
    abstract machine? (C&V?) Why would it be a problem if the abstract machine
    first stored the new value of `y', then read that same value again and
    stored it in `x'?

    The rules (6.5#2) don't forbit that an object is read an arbitrary number
    of times between two sequence points, as long as it is only /modified/
    once and only read to determine its new value. For example, I think in
    this statement (which has defined behavior)

    i = i + i + i + i + i;

    the abstract machine would be allowed to read the value of `i' five times.

    Martin
     
    Martin Dickopp, Dec 31, 2003
    #8
  9. Martin Dickopp <> scribbled the following:
    > (Richard Bos) writes:
    >> (ozbear) wrote:
    >> > My question would equally apply, I think, to something like...
    >> >
    >> > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

    >>
    >> An additional point: it may seem that this causes undefined behaviour,
    >> because
    >>
    >> - a new value is computed for y (involving y, but that part is OK);
    >> - the value of y is then assigned to x, without an intervening
    >> sequence point.
    >>
    >> However, this is not what happens.


    > Even if it does, it's not UB according to 6.5#2. It's not forbitten to
    > modify two distinct objects without intervening sequence point, only to
    > modify the same object more than once.


    And to use the old value for anything other than computing the new
    value.

    --
    /-- Joona Palaste () ------------- Finland --------\
    \-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
    "And according to Occam's Toothbrush, we only need to optimise the most frequent
    instructions."
    - Teemu Kerola
     
    Joona I Palaste, Dec 31, 2003
    #9
  10. Martin Dickopp wrote:
    >
    > (1) The value of the object may be modified at most once.
    > (2) If the value of the object is modified at all, the previous value
    > may be used only to determine the new value.
    >
    > The standard gives two examples of undefined behavior:
    >
    > i = ++i + 1; violates (1), because the value of `i' is modified
    > twice.
    > a[i++] = i; violates (2). While `i' is modified only once, its
    > previous value is used to determine its storage
    > location (as opposed to its new value).
    >


    What about
    a[++i] = i;

    The standard states that the previous value can only be *read* to
    determine the value to be stored. Isn't it questionable wether or
    not the previous value (as in the value just before this statement)
    is read twice or once? Maybe we are looking at unspecified behaviour
    since it depends on exactly when i is incremented and the order
    of evaluation.

    --
    Thomas.
     
    Thomas Stegen, Dec 31, 2003
    #10
  11. ozbear

    Jack Klein Guest

    On Wed, 31 Dec 2003 15:34:22 +0000, Thomas Stegen
    <> wrote in comp.lang.c:

    > Martin Dickopp wrote:
    > >
    > > (1) The value of the object may be modified at most once.
    > > (2) If the value of the object is modified at all, the previous value
    > > may be used only to determine the new value.
    > >
    > > The standard gives two examples of undefined behavior:
    > >
    > > i = ++i + 1; violates (1), because the value of `i' is modified
    > > twice.
    > > a[i++] = i; violates (2). While `i' is modified only once, its
    > > previous value is used to determine its storage
    > > location (as opposed to its new value).
    > >

    >
    > What about
    > a[++i] = i;
    >
    > The standard states that the previous value can only be *read* to
    > determine the value to be stored. Isn't it questionable wether or
    > not the previous value (as in the value just before this statement)
    > is read twice or once? Maybe we are looking at unspecified behaviour
    > since it depends on exactly when i is incremented and the order
    > of evaluation.


    Nope, absolutely undefined, per Martin's #2 above. The RHS of the
    assignment reads the value of i outside of the expression on the LHS
    that uses it to compute the new value.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c /faq
     
    Jack Klein, Dec 31, 2003
    #11
  12. ozbear

    Jack Klein Guest

    On 31 Dec 2003 12:29:29 +0100, Martin Dickopp
    <> wrote in comp.lang.c:

    > (Richard Bos) writes:
    >
    > > (ozbear) wrote:
    > >
    > > > My question would equally apply, I think, to something like...
    > > >
    > > > x = y = (y+y2)/2; /* ok, not ok, or bad analogy? */

    > >
    > > An additional point: it may seem that this causes undefined behaviour,
    > > because
    > >
    > > - a new value is computed for y (involving y, but that part is OK);
    > > - the value of y is then assigned to x, without an intervening
    > > sequence point.
    > >
    > > However, this is not what happens.

    >
    > Even if it does, it's not UB according to 6.5#2. It's not forbitten to
    > modify two distinct objects without intervening sequence point, only to
    > modify the same object more than once.
    >
    > > _This_ is:
    > >
    > > - a new value is computed for y (involving the old y in an OK manner);
    > > - that same _value_ is also the value of the assignment _expression_,
    > > which is then assigned to x.
    > >
    > > IOW, the evaluation of the inner assignment expression does not, in the
    > > abstract machine, read y again; it evaluates its right hand side, and
    > > then _both_ assigns this to y _and_ passes it on to the outer
    > > assignment.

    >
    > Does the standard really guarantee that `y' is only read once in the
    > abstract machine? (C&V?) Why would it be a problem if the abstract machine
    > first stored the new value of `y', then read that same value again and
    > stored it in `x'?


    The standard does not guarantee that 'y' is only read once, unless it
    is volatile, but paragraph 3 of 6.5.16 states:

    "An assignment operator stores a value in the object designated by the
    left operand. An assignment expression has the value of the left
    operand after the assignment, but is not an lvalue."

    Note that what is stored in 'x' is the value yielded by the original
    value after conversion (if necessary) to the type of 'y'. The as-if
    rule allows the implementation to read 'y' more than once as long as
    'y' is not volatile, since the result is the same, but if it does so
    must do so after the assignment to produce the correct value.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c /faq
     
    Jack Klein, Dec 31, 2003
    #12
  13. Jack Klein wrote:

    > On Wed, 31 Dec 2003 15:34:22 +0000, Thomas Stegen
    > <> wrote in comp.lang.c:
    >
    >
    >>Martin Dickopp wrote:
    >>
    >>> (1) The value of the object may be modified at most once.
    >>> (2) If the value of the object is modified at all, the previous value
    >>> may be used only to determine the new value.

    [snip]
    >>What about
    >> a[++i] = i;

    [snip]


    > Nope, absolutely undefined,


    I think it is undefined too.

    > per Martin's #2 above.


    But I am not sure this is the reason. Because it is the prior value
    that cannot be read for other reasons than determining the new value.

    > The RHS of the
    > assignment reads the value of i outside of the expression on the LHS
    > that uses it to compute the new value.


    The value assigned is not necessarily the prior value, is my point.
    This value is probably undefined though, since it only needs to be
    incremented before the next sequence point.

    My point is that the above is undefined, but I am not sure if it is
    6.5#2 (C99) that is the clause that causes this.

    --
    Thomas.
     
    Thomas Stegen, Dec 31, 2003
    #13
  14. ozbear

    Jack Klein Guest

    On Wed, 31 Dec 2003 18:35:22 +0000, Thomas Stegen
    <> wrote in comp.lang.c:

    > Jack Klein wrote:
    >
    > > On Wed, 31 Dec 2003 15:34:22 +0000, Thomas Stegen
    > > <> wrote in comp.lang.c:
    > >
    > >
    > >>Martin Dickopp wrote:
    > >>
    > >>> (1) The value of the object may be modified at most once.
    > >>> (2) If the value of the object is modified at all, the previous value
    > >>> may be used only to determine the new value.

    > [snip]
    > >>What about
    > >> a[++i] = i;

    > [snip]
    >
    >
    > > Nope, absolutely undefined,

    >
    > I think it is undefined too.
    >
    > > per Martin's #2 above.

    >
    > But I am not sure this is the reason. Because it is the prior value
    > that cannot be read for other reasons than determining the new value.
    >
    > > The RHS of the
    > > assignment reads the value of i outside of the expression on the LHS
    > > that uses it to compute the new value.

    >
    > The value assigned is not necessarily the prior value, is my point.
    > This value is probably undefined though, since it only needs to be
    > incremented before the next sequence point.
    >
    > My point is that the above is undefined, but I am not sure if it is
    > 6.5#2 (C99) that is the clause that causes this.


    That's exactly the point of the wording from the standard, this is an
    EXACT quote from paragraph 2 of section 6.5 of the C standard:

    ========
    Between the previous and next sequence point an object shall have its
    stored value modified at most once by the evaluation of an expression.
    Furthermore, the prior value shall be read only to determine the value
    to be stored.
    ========

    Note the second sentence.

    Now in the expression under discussion:

    a[++i] = i;

    The read of the value 'i' on the left hand side is perfectly proper,
    it is used in the computation of the new value. The read of the value
    of 'i' on the right hand side causes undefined behavior because it is
    not involved in the calculation of the value finally assigned to 'i'.

    Unless you can contend that the RHS of the expression does not need to
    perform an lvalue-to-rvalue conversion, that is read the value of 'i',
    and I don't think you are doing so.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c /faq
     
    Jack Klein, Dec 31, 2003
    #14
  15. ozbear

    ozbear Guest

    Many thanks to all that replied.

    Oz
     
    ozbear, Dec 31, 2003
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    5
    Views:
    267
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=
    Dec 29, 2006
  2. dragoncoder
    Replies:
    33
    Views:
    1,043
    Pete Becker
    May 23, 2006
  3. WP
    Replies:
    12
    Views:
    459
    Richard Bos
    Aug 27, 2007
  4. , India
    Replies:
    10
    Views:
    478
  5. , India
    Replies:
    4
    Views:
    375
    James Kanze
    Nov 16, 2009
Loading...

Share This Page