Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #162588

Re: Working code

From Tim Rentsch <tr.17687@z991.linuxsc.com>
Newsgroups comp.lang.c
Subject Re: Working code
Date 2021-09-02 09:57 -0700
Organization A noiseless patient Spider
Message-ID <867dfyx6cu.fsf@linuxsc.com> (permalink)
References (2 earlier) <sgpi2p$kd1$1@dont-email.me> <slrnsj0nro.1o4.ike@rie.sdf.org> <8735qn1c3r.fsf@bsb.me.uk> <9h2YI.9458$2Q_3.2077@fx35.iad> <87ilzjywz0.fsf@bsb.me.uk>

Show all headers | View raw


Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> Richard Damon <Richard@Damon-Family.org> writes:
>
>> On 9/2/21 6:54 AM, Ben Bacarisse wrote:
>>
>>> Ike Naar <ike@rie.sdf.org> writes:
>>>
>>>> On 2021-09-02, Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
>>>>
>>>>> On 9/1/2021 4:58 PM, Tim Rentsch wrote:
>>>>>
>>>>>>> The following is simplified version of "working code":  it
>>>>>>> is more than 20 years old (probably closer to 30 years old)
>>>>>>> and apparently did what its author intended:
>>>>>>>
>>>>>>> int (*handlers[2])();
>>>>>>>
>>>>>>> #define DO_IT(n)   ((p = handlers[n]) ? (*p)() : 0)
>>>>>>>
>>>>>>> static void foo() {
>>>>>>>      register int (*p)();
>>>>>>>      register int bar = DO_IT(0) | DO_IT(1);
>>>>>>>      /* ... */
>>>>>>>      /* Use of bar */
>>>>>>> }
>>>>>>>
>>>>>>> /* Code that fills 'handlers' and calls foo() */
>>>>>>>
>>>>>>> I wonder what you think about this code?
>>>>>>
>>>>>> I think it has undefined behavior, and needlessly so:
>>>>>>
>>>>>>      #define DO_IT(n)   (handlers[n] ? handlers[n]() : 0)
>>>>>>
>>>>>>      ...
>>>>>
>>>>> That intermediate variable `p` is indeed completely unnecessary.
>>>>> But where did you find undefined behavior in the original
>>>>> version?
>>>>
>>>> In the expression 'DO_IT(0) | DO_IT(1);' p is being modified more
>>>> than once.  The behaviour of the expression depends on how its
>>>> subexpressions are sequenced.
>>>
>>> There is a sequence point after each assignment.  Am I missing
>>> something?
>>
>> No, there is a dependency that that assignment can't happen until
>> after the right hand side is evalutated, but no full sequence
>> point.
>
> What's a full sequence point?

The C standard doesn't use the term "full sequence point".  It
does define the term "full expression", which includes expression
statements and declaration initializers (and a few others), and
says there is a sequence point at the end of each full expression.

>> There is no sequencing between the assignments of DO_IT(0) and
>> DO_IT(1) and very importantly between the (*p)()s, both
>> assignements can happen then both (*p)() happen, using whichever
>> value of p was assigned last.
>
> There is one between each assignment and the corresponding use,
> but you are saying that that is not enough.  Have I got that about
> right?  Is this derived from the new C11 "sequenced before"
> wording that replaced the old wording C99 or was it UB in C99 as
> well?

To answer the second question first, the new phrasing in C11
using "sequenced before", etc, clarified the rules but did not
the change the rules.  The example here is just as much UB in
C90 and C99 as it is in C11.

Regarding the first question, the problem is that there are two
assignments to the variable 'p' without any sequence point
between the two assignments.  It is the assignments that cause
the problem;  the subsequent uses don't matter.  An AST for the
expression would look something like this:

                   "bitwise or(|)"
                  /               \
                 /                 \
                /                   \
               /                     \
             ?:                       ?:
          /   |  \                 /   |  \   
         /    |   \               /    |   \  
        /     |    \             /     |    \ 
     p=...  (*p)()  0         p=...  (*p)()  0

A bitwise-or operator has no sequencing, so it is free to
evaluate its subexpressions simultaneously.  The ?: operator on
the left branch does impose a sequencing between 'p=...' and its
other operands, and similarly for the right branch.  However, no
sequencing is imposed between the first 'p=...' and the second
'p=...', because the bitwise-or doesn't specify an order of
evaluation, and the two ?: operators impose an ordering only
within each subexpression, not between the two subexpressions.

If the bitwise-or ('|') were replaced with a logical-or ('||')
then there would be no undefined behavior.  Of course doing that
would change the semantics.

If anyone is interested the principle here is addressed in an
early defect report a few years after C90 was issued:

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_087.html

Back to comp.lang.c | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

Working code antispam@math.uni.wroc.pl - 2021-09-01 22:23 +0000
  Re: Working code Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-09-01 16:58 -0700
    Re: Working code Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-09-01 20:57 -0700
      Re: Working code Ike Naar <ike@rie.sdf.org> - 2021-09-02 05:22 +0000
        Re: Working code Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-09-01 22:33 -0700
        Re: Working code Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-09-02 11:54 +0100
          Re: Working code Richard Damon <Richard@Damon-Family.org> - 2021-09-02 07:08 -0400
            Re: Working code Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-09-02 13:37 +0100
              Re: Working code James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-09-02 12:03 -0400
              Re: Working code Tim Rentsch <tr.17687@z991.linuxsc.com> - 2021-09-02 09:57 -0700
  Re: Working code Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-09-01 21:02 -0700
    Re: Working code John McCue <jmccue@obsd2.mhome.org> - 2021-09-02 13:31 +0000

csiph-web