1

3.10/10

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

  • the dynamic type of the object,
  • a cv-qualified version of the dynamic type of the object,
  • a type similar (as defined in 4.4) to the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to the dynamic type of the object,
  • a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
  • a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
  • a char or unsigned char type.
Ayrosa
  • 3,385
  • 1
  • 18
  • 29
  • I'm not entirely sure what you're looking for. Is it something like `int i = 42; double j = reinterpret_cast(std::move(i));`, where we produce an xvalue via `std::move(i)`, and then violate the strict aliasing rule? – dyp Dec 15 '14 at 20:48
  • All the examples I've seen of violations to the strict aliasing rule use lvalues (dereferencing a pointer). I'm curious to see one example using an xvalue, if possible. AFAICT, I don't think your example characterizes strict aliasing. In fact it doesn't compile. – Ayrosa Dec 15 '14 at 21:00
  • Well, this is interesting. Yes, I should have checked that it compiles, but it actually *does* compile on clang++. Not on g++4.9. [Live example](http://coliru.stacked-crooked.com/a/e1382895e9a81154). (I would guess this is a g++ bug.) The aliasing issue in my example is that the stored value of an object of type `int` (named `i`) is accessed through an xvalue of type `double`. -- Edit, ah, ok it is a C++11 vs C++14 issue. See http://stackoverflow.com/q/26793072 Here's a similar aliasing issue written for C++11: http://coliru.stacked-crooked.com/a/d4d04f41104f10bc – dyp Dec 15 '14 at 21:05
  • @dyp I'm almost convinced that your example typifies an aliasing issue. Let's wait to see if somebody comes with a different idea. Thanks. – Ayrosa Dec 15 '14 at 21:36

1 Answers1

-4

Readers should be aware that the paragraph cited by the OP is a religious issue, as the basis of a disputed behavior of the g++ compiler. Any answer sowing doubt on the accuracy or completeness of this paragraph (and it's neither) will generally get downvoted on SO.

Here's an example of UB according to the paragraph you're citing:

struct X { int i; };

auto main() -> int
{
    X o{ 0 };
    return reinterpret_cast<int&>( o );
}

Considering each possibility in C++11 §3.10/10 in order:

  • Is “the dynamic type of the object” o an int?
    No, the dynamic type is an X.

  • Is int perhaps “a cv-qualified version” of the dynamic type X?
    No, X is not an int, cv-qualified or not.

  • Is int “a type similar (as defined in 4.4) to the dynamic type of the object”?
    Again, no. 4.4 deals with multi-level cv-qualification.

  • Well, is int “a type that is the signed or unsigned type corresponding to the dynamic type of the object”?
    No, there are no signed or unsigned versions of a class type like X.

  • So what about “a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object”?
    No.

  • Well, is int perhaps “an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union)”?
    No, not that either.

  • So maybe int is “a type that is a (possibly cv-qualified) base class type of the dynamic type of the object”?
    No, an int can’t be a base class.

  • Finally, is int “a char or unsigned char type”?
    No.

And this exhausts all possibilities, proving that according to that paragraph in isolation, this code has Undefined Behavior.

However, this code is guaranteed to work by another part of the standard (I guess mainly for C compatibility).

So, the paragraph you cite isn't 100% good even for the completely platform-independent formal.


Edit: "dyp" asked in a comment how this relates to use of an xvalue. An xvalue is a glvalue, so one can just substitute an xvalue for the lvalue expression o. An example of such xvalue is an rvalue reference returned from a function, e.g. from std::move:

#include <utility>
using std::move;

struct X { int i; };

template< class T >
auto ref( T&& r ) -> T& { return r; }

auto main() -> int
{
    X o{ 0 };
    return reinterpret_cast<int&>( ref( move( o ) ) );
}

All this does is however to mask the essentials.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 1
    Where is the xvalue / is there an xvalue in your answer? – dyp Dec 15 '14 at 20:35
  • 1
    Also, this is not an example of a possible strict-aliasing failure. – Ayrosa Dec 15 '14 at 20:44
  • Isn't this in fact accessing the stored value of an `int` object through a glvalue of type `int`? I'll allow that the `int&` is obtained in a roundabout way via the pointer-to-first-member-of-standard-layout-class rule, but accessing an `int` through an `int` glvalue does not violate the strictures of 3.10. – Casey Dec 15 '14 at 21:11
  • @Casey: the 3rd last point covers the opposite conversion. since the list is presumed exhaustive, this conversion isn't in the list. – Cheers and hth. - Alf Dec 15 '14 at 22:07
  • @dyp: there's an lvalue expression `o`, which is a glvalue, which is what the quoted paragraph is about. an xvalue is also a glvalue. you can just substitute that (and change the cast accordingly) if you want. – Cheers and hth. - Alf Dec 15 '14 at 22:12
  • The first point covers it: "the dynamic type of the object." The `i` subobject of `o` has type `int`. This program accesses its stored value through a glvalue of type `int`. – Casey Dec 15 '14 at 22:12
  • @Casey: Nope. If the 1st point covered this, then it would also cover the 3rd last point, which would not need to be in the list. The 3rd last point is however vague enough that you can easily construct an example that clearly has UB and yet is OK wrt. to that point, so that's a second example of how inexact this list is. – Cheers and hth. - Alf Dec 15 '14 at 22:16
  • It's quite unfortunate the OP does not contain a question; however the title does. And the title is asking for an xvalue and UB; neither can I find in your answer. – dyp Dec 15 '14 at 22:50
  • 1
    @dyp: I explained how you could do that, but OK, I've now added it. Note that it's not essential to what my answer was and is about. That detail is IMHO not interesting, and as I see it just tends to obscure things by adding more irrelevant complexity. – Cheers and hth. - Alf Dec 15 '14 at 23:01
  • I know that you and me (and others) know what is meant with that substitution, but it's not clear to me if the OP knows that. I appreciate your edit; but I'm still concerned about two points: 1) Arguably, the (read) access happens through an lvalue, not an xvalue. The fact that there's an xvalue involved in a sub-expression is probably irrelevant to the strict aliasing rule. That's why my example is inverted, first `reinterpret_cast`, then conversion to an xvalue, then access. 2) It still does not contain UB, although the OP requested it. Why do you use that standard-layout guarantee here? – dyp Dec 15 '14 at 23:19
  • @dyp: I added (silly) proof that it's UB according to the paragraph the OP cited. It is of course not really UB, since it's guaranteed behavior elsewhere. The standard is simply inconsistent here; it's one of several flaws of this paragraph (I mentioned another one above). – Cheers and hth. - Alf Dec 15 '14 at 23:21
  • @dyp: re "The fact that there's an xvalue involved in a sub-expression is probably irrelevant to the strict aliasing rule", yes, the xvalue just obscures by adding complexity; the rule, or OP's cited paragraph, is about glvalues. – Cheers and hth. - Alf Dec 15 '14 at 23:39
  • I, for one didn't upvote because I still don't understand precisely what the OP wants. From what I suspect, it's still not quite what you've shown in your answer, since the (g)lvalue-to-rvalue conversion is applied to an lvalue in the return-statement. Also, I'm not sure if, as Casey stated, you're not accessing a glvalue of type `int` here. The semantics of that `reinterpret_cast` aren't completely clear to me (two `static_cast`s, involving a value of type `void*` which is an address, and it's guaranteed that `(void*)&o == (void*)&o.i`). But this is only a subtlety, I agree it's not UB. – dyp Dec 16 '14 at 00:54
  • @dyp: Re the Casey argument, an object can't have more than one dynamic type, except via derived/base relationships (not present here). The object has dynamic type `X`, and that's what goes into the first point of the paragraph. Casey's argument is simply a wish that this paragraph should include a case also for the first-item-of case, and my point about that is that the paragraph doesn't actually contain that case, even though it's intended to be exhaustive. – Cheers and hth. - Alf Dec 16 '14 at 01:07
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/66950/discussion-between-dyp-and-cheers-and-hth-alf). – dyp Dec 16 '14 at 01:09
  • Casey's argument is that the object being accessed is the integer subject `i` of `X`, which has dynamic type `int`. – Casey Dec 19 '14 at 14:02
  • @Casey: You're right about "the object being accessed is the integer subject i of X, which has dynamic type int", and that's noted in the answer. The additional claim from you, which is proved wrong in the answer, in detail, is the claim that that's covered by the paragraph the OP cited. It's not: the guarantee of no padding before first item, and of reinterpret_cast yielding the same address, covered elsewhere (much later) in the standard, not here. – Cheers and hth. - Alf Dec 19 '14 at 18:49
  • It's clear from even a superficial reading that 3.10/10.1 allows accessing the stored value of an object of type `int` through a glvalue of type `int`, which we both seem to agree is the behavior of your program. The details of how that glvalue is obtained and proving that it is valid require a convoluted trip through 9.2/19, 5.2.10/11 and /7, and 5.2.9/13 - but those details are immaterial to the application of 3.10/10. Accessing the stored value of an `int` through an `int` glvalue conforms to 3.10/10 regardless of how that glvalue is obtained. – Casey Dec 19 '14 at 20:26
  • @Casey "which we both seem to agree is the behavior of your program." that's proved false. more precisely, it's not true that that's the behavior according to the OP's cited paragraph. you're not honest. you're misdirecting readers by intentionally conflating issues, after being presented with detailed proof that you're wrong. if you were honest you would start with that proof, trying to find some fault. you haven't – Cheers and hth. - Alf Dec 19 '14 at 20:33
  • I think the disconnect here is "The object has dynamic type `X`, and that's what goes into the first point of the paragraph." I maintain that the object being accessed here is not `o` with type `X`, but the subobject `o.i` with type `int`. Thanks to 9.2/19, `reinterpret_cast(o)` is simply a complicated way to spell `o.i`. – Casey Dec 19 '14 at 21:13
  • 1
    There are many ways to obtain a glvalue that refers to `o.i`. `reinterpret_cast(o)`, `o.i`, `o.*&X::i`, `int& foo = o.i;`, etc. 3.10/10 doesn't describe the behavior of any of them - other parts of the standard do - it only describes what happens when the stored value of an object is accessed through such a glvalue. As far as 3.10/10 is concerned, there is no difference between `return reinterpret_cast(o);`, `return o.i;`, `return o.*&X::i;`, or `return foo;`. They all access the stored value of an `int` through a glvalue of type `int`. – Casey Dec 19 '14 at 21:31
  • @casey: The code here directly involves `o`, not `o.i`. The paragraph cited by the OP does not allow you to equate `o` with `o.i`. Detailed proof is given above in the answer, checking each case of that paragraph in order: none of those cases give you permission. – Cheers and hth. - Alf Dec 19 '14 at 22:14
  • Both of you have interesting points. But the better point being: this is badly written, and SO's crowd is way too uptight. I'm also in the process of suffering from that chapter here https://stackoverflow.com/a/57318684/893406 – v.oddou Aug 02 '19 at 05:43