C++ Logo

std-discussion

Advanced search

Re: Access to virtual base class subobjects via derived classes

From: Matthew House <mattlloydhouse_at_[hidden]>
Date: Sun, 25 Dec 2022 22:58:10 -0500
On Sun, Dec 25, 2022 at 5:28 PM Thiago Macieira via Std-Discussion
<std-discussion_at_[hidden]> wrote:
> > What do you mean? The wording says that the value is unspecified,
> > not that the behavior is undefined. At worst, the program could
> > have implementation-defined behavior from reading an invalid
> > pointer value.
>
> I meant that values can't suddenly become unspecified after being
> specified, short of memory deallocation and other end-of-lifetime
> operations, which aren't the case here. Therefore, if this code was
> meant to be invalid, then it can't be simply "unspecified", it has
> to go all the way to UB.

Thank you, now I see what you mean. The value being unspecified would
be an oddly weak restriction if aliasing the this pointer with outside
pointers were meant to be banned entirely. Given the original context
of const objects under construction, I wonder if the intent may have
been to grant compilers the liberty to replace accesses to const
objects' data members with the ultimate immutable values of those
members, while still allowing programs to perform such accesses in the
constructor as long as their behavior does not depend on the resulting
values.

> Though another reading could say that your program is fully
> specified because the variables are obtained from the constructor's
> this pointer in all its bases and incarnations. It doesn't stop
> being valid or specified just because it's crossed into another
> base. That would mean the issue we've been discussing on cpplang is
> either a plain compiler bug or has a different source.
>
> I still think some firmer language here would be welcome. For
> example, it should be clear if the compilers are allowed to assume
> pointers passed into the constructor can alias the object's storage
> or not, and in particular whether this applies to virtual base
> sub-objects and the not-in-charge constructors.

I was unaware of the discussion on Cpplang (or, for that matter, of
the existence of Cpplang); I independently stumbled on this oddity
while trying to build a mental model of which operations can be
performed on objects at each point of their construction. I should
probably look into that Cpplang issue, if it's relevant here.

Putting that aside, such a permissive reading of the current wording
seems very "magical" to me; it goes far beyond the literal language
used in the paragraph, in such a way that it can't really be derived
from first principles without perfect knowledge of the intent. If we
want to allow either or both of example programs, I think that firmer
language here is a necessity.

The fuzziest part of the strict reading is probably the unspecified
concept of a glvalue being "indirectly obtained from" a pointer.
Looking at the rest of the Standard, to "obtain" something usually
means to receive it directly as the result of a particular operation.
Used here, does it mean that the pointer must have been used at some
arbitrary point when forming the glvalue? Does it mean that the
glvalue's address must be "based on" the pointer in the sense of ISO
C? Does it invoke some other abstract notion of pointer provenance?
(For instance, may one obtain the glvalue from a uintptr_t obtained
from the pointer?) The complete answer to this is not at all apparent
from first principles.


On Sun, Dec 25, 2022 at 5:28 PM Thiago Macieira via Std-Discussion
<std-discussion_at_[hidden]> wrote:
>
> On Sunday, 25 December 2022 14:33:36 -03 Matthew House via Std-Discussion
> wrote:
> > > I add that this is something UB could do, but not unspecified.
> >
> > What do you mean? The wording says that the value is unspecified, not
> > that the behavior is undefined. At worst, the program could have
> > implementation-defined behavior from reading an invalid pointer value.
>
> I meant that values can't suddenly become unspecified after being specified,
> short of memory deallocation and other end-of-lifetime operations, which
> aren't the case here. Therefore, if this code was meant to be invalid, then it
> can't be simply "unspecified", it has to go all the way to UB.
>
> > This paragraph has been around for a long time, and to me it appears
> > not to have been properly updated to account for virtual base classes.
> > In ISO C++98 (12.1 [class.ctor] para. 15), it applied only to const
> > objects under construction. In ISO C++17, it was expanded to apply to
> > all objects under construction, in response to DR 2271. Based on the
> > examples, the rationale appears to be to prevent programs from
> > referring to the object under construction from external sources such
> > as global variables. However, its wording is broad enough to also
> > prevent a constructor from accessing a pointer into a virtual base
> > class subobject, if that pointer was otherwise validly obtained from
> > the constructor of a derived class.
>
> Agreed.
>
> Though another reading could say that your program is fully specified because
> the variables are obtained from the constructor's this pointer in all its
> bases and incarnations. It doesn't stop being valid or specified just because
> it's crossed into another base. That would mean the issue we've been
> discussing on cpplang is either a plain compiler bug or has a different source.
>
> I still think some firmer language here would be welcome. For example, it
> should be clear if the compilers are allowed to assume pointers passed into
> the constructor can alias the object's storage or not, and in particular
> whether this applies to virtual base sub-objects and the not-in-charge
> constructors.
>
> --
> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
> Software Architect - Intel DCAI Cloud Engineering
>
>
>
> --
> Std-Discussion mailing list
> Std-Discussion_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-discussion

Received on 2022-12-26 03:58:22