2017-08-11 13:47 GMT+02:00 Jens Maurer <Jens.Maurer@gmx.net>:
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;