C++ Logo

sg12

Advanced search

Re: [ub] Is dereferencing this pointer a UB?

From: Andrzej Krzemienski <akrzemi1_at_[hidden]>
Date: Sat, 12 Aug 2017 10:52:00 +0200
2017-08-11 13:47 GMT+02:00 Jens Maurer <Jens.Maurer_at_[hidden]>:

> On 08/11/2017 09:58 AM, Andrzej Krzemienski wrote:
> > Hi SG12 Members,
> >
> > I already asked this question in ISO C++ Standard - Discussion (
> https://groups.google.com/a/isocpp.org/forum/?fromgroups=#
> !topic/std-discussion/UbROFU6Fs0E <https://groups.google.com/a/
> isocpp.org/forum/?fromgroups=#%21topic/std-discussion/UbROFU6Fs0E>), but
> maybe this list is better suited.
> >
> > UB-sanitizer reports a runtime error for the following program:
> >
> > ```
> > struct B;
> >
> > struct I {
> > virtual void f() {}; // <- virtual
> > };
> >
> > struct A : I {
> > A();
> > };
> >
> > struct B : A {
> > };
> >
> > A::A() { *static_cast<B*>(this); } // <- UB in static_cast
> >
> > int main()
> > {
> > B{};
> > }
> > ```
> >
> > My question: is UB-sanitizer correct? Is this a UB according to the
> standard? And if so, could you point me to the relevant sections?
>
> The dereference here is immaterial; it just converts a pointer to an
> lvalue,
> neither of which accesses the pointed-to value per se.
>
> The conversion happens while A and B are being constructed, and we have
> special rules in 15.7 [class.cdtor] for that. Of particular interest
> is p2, which discusses conversions from B* to A*, but 8.2.9
> [expr.static.cast]
> indirectly refers to that case when discussing the A* to B* case.
>
> Both the construction of B and A have started at the point in question,
> so it seems to me the pointer conversion is, in fact, valid.
>

Thanks for your analysis. Interestingly, I have now arrived at the opposite
conclusion, based on [expr.static.cast]/p11 and [class.dtor]/p16, and some
interpolation of my own. Let me share my reasoning, and tell me what you
make of it.

[class.cdtor]/p2 talks about the upcast, so I would rather go with
[expr.static.cast]/p11 which talks about the downcast. The latter says the
downcast is UB-free if the casted-from object O is casted to an object that
contains O as its subobject. Term "object" implies a relation to run-time
(life-time), there is just the question whether we mean "object lifetime
(after non-delegating constructor finishes and before the destructor
starts) or the "extended object time" (after constructor starts and before
destructor finishes).

Now, [class.dtor]/p16 says, "Once a destructor is invoked for an object,
the object no longer exists". This "exists" I find applicable to the
definition of class.cdtor]/p2. If we were considering the same downcast in
the *destructor* of A, I would have a clear answer. Now, there is no
similar statement when the object starts to "exist", but by analogy to
destructor, I would conclude that it starts to exist when the constructor
finises. Untill then, there is no object B in existence and therefore the
the static_cast condition that "the casted-from object O is casted to an
object that contains O as its subobject" is not satisfied.

Is the above reasoning correct?

Regards,
&rzej;

Received on 2017-08-12 10:52:04