Date: Sat, 20 Feb 2021 11:27:58 +0000
Am Samstag, den 20.02.2021, 12:10 +0100 schrieb Jens Maurer:
> On 20/02/2021 10.06, Uecker, Martin via Liaison wrote:
> > Am Samstag, den 20.02.2021, 09:30 +0100 schrieb Jens Gustedt via Liaison:
> > > Jens,
> > >
> > > on Fri, 19 Feb 2021 22:31:15 +0100 you (Jens Maurer via Liaison
> > > <liaison_at_[hidden]>) wrote:
> > >
> > > > So, for anything but "unsigned char", even looking at
> > > > an uninitialized value is undefined behavior in C++
> > > > (in C parlance, there might be a trap representation).
> > >
> > > It is a bit more complicated in C, because of this weird `register`
> > > rule and because of pointers:
> >
> > The C rules are a bit weird, but overall make sense to me.
> >
> > The C++ rules seem far more problematic: The forbid useful
> > behavior that C allows. For example, computing as hash for
> > a struct including padding bytes and comparing it later.
>
> Yes, that doesn't work reliably in C++.
>
> > I similar issue might exist for atomic_compare_exchange.
> > (I do not know what they did there to fix this).
>
> Specification-wise, we simply say that you ignore padding
> bytes in the comparison ([atomics.types.operations] p23;
> look for "value representation"). Practically speaking, the
> implementation might invoke compiler magic to reliably zero
> the padding bytes before doing the comparison.
>
> > At the same time it does not allow simple detection of
> > reads of uninitialized automatic variables because you
> > to take all this weird rules for unsigned char into
> > account.
>
> I think the C++ rules here are fairly tractable, since you
> only need to analyze a single expression at a time for
> determining whether the uninitialized "unsigned char"
> read is a good one or a bad one.
I agree it is not a major problem.
> > This does strike me as very unfortunate design
> > choice (which also made language more different from C).
>
> The "could have been declared with register" rule in C
> doesn't seem friendly either, because a seemingly benign
> no-op has spooky effects at a distance:
>
> void f()
> {
> int i;
>
> [... some lines of code...]
>
> if (false)
> (void)&i; // ah, address was taken, go back to the beginning of "f" and re-analyze all the
> code
> }
Compilers need to track anyway whether the address was
taken so this information is readily available. Also
initialization and use can be at a distance, so deciding
whether a variable is (potentially) read before
initialization is a global property of a function anyway.
> (C++ doesn't have "register" anymore, because compilers can do it
> much better automatically.)
Yes, although there is no real need to refer to
register when formulating this rule, it is just
done this way in C.
BTW: I find "register" in C useful to express that the
address can not be taken, similar how "const" can
be used to express that writes are not allowed.
This is less about helping the compiler than
about expressing constraints.
There are also cases where the property that an
address is not taken can not be derived
by a compiler, i.e. for file-scope variables,
although for some reason we do not allow to use
register in C.
Best,
Martin
> On 20/02/2021 10.06, Uecker, Martin via Liaison wrote:
> > Am Samstag, den 20.02.2021, 09:30 +0100 schrieb Jens Gustedt via Liaison:
> > > Jens,
> > >
> > > on Fri, 19 Feb 2021 22:31:15 +0100 you (Jens Maurer via Liaison
> > > <liaison_at_[hidden]>) wrote:
> > >
> > > > So, for anything but "unsigned char", even looking at
> > > > an uninitialized value is undefined behavior in C++
> > > > (in C parlance, there might be a trap representation).
> > >
> > > It is a bit more complicated in C, because of this weird `register`
> > > rule and because of pointers:
> >
> > The C rules are a bit weird, but overall make sense to me.
> >
> > The C++ rules seem far more problematic: The forbid useful
> > behavior that C allows. For example, computing as hash for
> > a struct including padding bytes and comparing it later.
>
> Yes, that doesn't work reliably in C++.
>
> > I similar issue might exist for atomic_compare_exchange.
> > (I do not know what they did there to fix this).
>
> Specification-wise, we simply say that you ignore padding
> bytes in the comparison ([atomics.types.operations] p23;
> look for "value representation"). Practically speaking, the
> implementation might invoke compiler magic to reliably zero
> the padding bytes before doing the comparison.
>
> > At the same time it does not allow simple detection of
> > reads of uninitialized automatic variables because you
> > to take all this weird rules for unsigned char into
> > account.
>
> I think the C++ rules here are fairly tractable, since you
> only need to analyze a single expression at a time for
> determining whether the uninitialized "unsigned char"
> read is a good one or a bad one.
I agree it is not a major problem.
> > This does strike me as very unfortunate design
> > choice (which also made language more different from C).
>
> The "could have been declared with register" rule in C
> doesn't seem friendly either, because a seemingly benign
> no-op has spooky effects at a distance:
>
> void f()
> {
> int i;
>
> [... some lines of code...]
>
> if (false)
> (void)&i; // ah, address was taken, go back to the beginning of "f" and re-analyze all the
> code
> }
Compilers need to track anyway whether the address was
taken so this information is readily available. Also
initialization and use can be at a distance, so deciding
whether a variable is (potentially) read before
initialization is a global property of a function anyway.
> (C++ doesn't have "register" anymore, because compilers can do it
> much better automatically.)
Yes, although there is no real need to refer to
register when formulating this rule, it is just
done this way in C.
BTW: I find "register" in C useful to express that the
address can not be taken, similar how "const" can
be used to express that writes are not allowed.
This is less about helping the compiler than
about expressing constraints.
There are also cases where the property that an
address is not taken can not be derived
by a compiler, i.e. for file-scope variables,
although for some reason we do not allow to use
register in C.
Best,
Martin
Received on 2021-02-20 05:28:06