12

In the c++ standard, in [basic.lval]/11.6 says:

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:[...]

  • an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),[...]

This sentence is part of the strict-aliasing rule.

Does it allow us to alias through class member access?

class A{ //"casted to" aggregate
  int i;
  float g;
  };

int j=10;
int l = reinterpret_cast<A*>(&j)->i;

According to the standard, an object value is only accessed if the object is subject to lvalue-to-rvalue-conversion [conv.lval]/2.

[expr.ref] does not stipulate that the object-expression must refer to an object of that type, only that the glvalue must have class type (the object-expression is the expression at the left of the dot "."). Nevertheless there is a word that recurrently appears in sentence related to member access which may imply constraint on the program that I overlooked. For example [expr.ref]/4.1:

If E2 is a static data member and the type of E2 is T, then E1.E2 is an lvalue; the expression designates the named member of the class.

Could "designates" means that this member is within its lifetime and that I cannot use class member access to perfom aliasing? Or is it allowed by [basic.lval]/11.6?

Community
  • 1
  • 1
Oliv
  • 17,610
  • 1
  • 29
  • 72
  • I think that you need to analyze pointer-interconvertibility as well (`&j` is pointer-interconvertible to `A*`). – geza Nov 05 '18 at 11:15
  • Btw, you say "class" in the title, and give `union` in the question. Is this a mistake? – geza Nov 05 '18 at 11:17
  • @geza Unions are classes. – Lightness Races in Orbit Nov 05 '18 at 11:24
  • I made this mistake while splitting a large question in two: this other question is about union:https://stackoverflow.com/questions/53151044/can-we-access-a-member-of-a-non-existing-union?noredirect=1#comment93192830_53151044 – Oliv Nov 05 '18 at 11:26
  • @LightnessRacesinOrbit: yes, but it could matter whether it is a union or a class. It seemed a mistake, and indeed it was :) – geza Nov 05 '18 at 11:26
  • 2
    There is no "union or a class", since unions are classes. :) – Lightness Races in Orbit Nov 05 '18 at 11:27
  • @Oliv: are you sure about pointer-interconvertibility? `i` is an `int` member, `A` has standard-layout, so... – geza Nov 05 '18 at 11:30
  • @geza I have few doubts. pointer-interconvertibility is about two objects, the standard says: *Two objects a and b are pointer-interconvertible* but there are no two objects here. This rule would apply if `j` where a subobject of an existing object of type `A`. On the other hand [basic.lval]/11.6 does not requires two objects to exist, it just about the type of the glvalue through which is performed the access to the value of an existing object. – Oliv Nov 05 '18 at 11:37
  • @LightnessRacesinOrbit: in the example, it could matter whether `A` is a `class`, or a `union`. – geza Nov 05 '18 at 11:39
  • @Oliv: okay then, let's wait for a high-level expert to answer this question :) – geza Nov 05 '18 at 11:42
  • @LightnessRacesinOrbit: yes. For someone who don't read the question carefully. – geza Nov 05 '18 at 11:47
  • @geza Soon will be the sun rise in America. I hope to get an answer in few hours. – Oliv Nov 05 '18 at 11:49
  • 2
    @geza: Quite the contrary - since the question is tagged [tag:language-lawyer], a careful reading is mandated, and a careful reader will note that "class" includes unions unless otherwise qualified. – Lightness Races in Orbit Nov 05 '18 at 11:52
  • 1
    I have to think about it some more but I believe the case it was meant to support was the example I give in [my strict aliasing answer here](https://stackoverflow.com/a/51228315/1708801) for that paragraph. Also see the [paper I reference here](https://stackoverflow.com/a/27914489/1708801) – Shafik Yaghmour Nov 05 '18 at 16:54
  • @ShafikYaghmour In C this [basic.lval]/11.6 rule makes much more sense. In C++, I'am troubled by the example you give for 11.6. Even if this rule (11.6) was not there, `fp.x` could be an alias for `ip` no? And even if `fp` were not an aggregate, `fp.x` could be an alias for `ip`? – Oliv Nov 05 '18 at 18:10
  • @Oliv: In C, N1570 5.6p7 gives does not give general permission to access a struct or union object with an lvalue of member type; nor does it grant any special permission for access via member-access expression. This would not be a problem if the footnote were recognized as indicating that compilers are only meant to use the rule to indicate when they must allow for the possibility that seemingly-unrelated lvalues might alias. Rather than interpreting the rule that way, however, gcc and clang behave as though they must give blanket permission to access structs via member-type lvalues. – supercat Nov 06 '18 at 15:56
  • @supercat I understand the intent of this rule now, my reading of the standard was two much literal. – Oliv Nov 06 '18 at 16:09
  • @Oliv: You may understand the intent of the rule, but the authors of gcc and clang seem deliberately oblivious to it, and also to the Spirit of C which is discussed in the Rationale, and includes the key principle "Don't prevent the programmer from doing what needs to be done". Among implementations intended for different purposes, "what needs to be done" will vary, and the authors of the Standard wanted to avoid mandating "one size fits all". Unfortunately, gcc/clang interpret as saying that programmers have no right to expect compilers to recognize any needs that aren't universal. – supercat Nov 06 '18 at 16:46
  • @supercat I don't know C, and the C standard, I can't find 5.6p7 in N1570. Where can I find the Rationale? I'd like to be able to follow you. I am really interested in understanding how deviation from the spirit to some literal interpretation (like I did) happen. – Oliv Nov 06 '18 at 19:23
  • @Oliv: Sorry. Typo. I meant https://port70.net/~nsz/c/c11/n1570.html#6.5p7 [6.5p7]. Type `C Rationale` into google to find http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf to receive a document that should be required reading for people intending or claiming to write quality C implementations. – supercat Nov 06 '18 at 19:36
  • @ShafikYaghmour [This answer](https://stackoverflow.com/a/53178541/5632316) from the associated question site core issue 2051, which says that 11.6 is subsumed by other rules in c++. – Oliv Nov 06 '18 at 19:47
  • @Oliv that is very different view point then is expressed in [this paper](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1520.htm) which still seems relevant and conflicts with conversations I have had with other committee members as well. The issue has been open since 2014 :-( – Shafik Yaghmour Nov 06 '18 at 19:54
  • 3
    [basic.lval]/11.6 is a negative rule. "If you do X, the behavior is undefined" doesn't mean "if you don't do X, the behavior is defined". That's [denying the antecedent](https://en.wikipedia.org/wiki/Denying_the_antecedent). – T.C. Nov 06 '18 at 21:38
  • @T.C. This is why I am trying to find what is allowed! – Oliv Nov 06 '18 at 21:48
  • @T.C. And the only thing that I thought could match was to perform an access to non static data member. (Calling a member function is not allowed). – Oliv Nov 06 '18 at 21:51
  • @T.C. Could your comment be an example of "Petitio principi"? – Oliv Nov 06 '18 at 21:57
  • @Oliv: Are you still interrested in an answer? What do you want to achieve? In particular, why do you want to cast an int value to a class, and then access member of the class? If you would use a union than it would make a bit more sense. However, there may be an easier way, anyway. – Jörg Brüggmann Dec 20 '18 at 17:12
  • @Jörg'Wuwei'Brüggmann Actually I was wondering why there is this paragraph in the standard. Finally it is a relics of C, or depending on the sensibility, a rule that allow "access" to an aggregate member without strict aliasing rule violation. There is an open core language issue for that but it will probably stay in the standard because all committee members don't have the same "sensibility" on the subject. – Oliv Dec 20 '18 at 18:25
  • @Oliv: All that should have been necessary for the C Standard would have been to apply the footnote and the Spirit of C "Don't prevent the programmer from doing what needs to be done" as implying that quality implementations should use the rule for the purpose of identifying *when seemingly-unrelated lvalues may or may not alias*, and not for the purpose of ignoring the fact that an access to an lvalue which is visibly derived from some object *is* an access to that object. – supercat Jan 01 '19 at 20:49

1 Answers1

1

For non-static data member, the word is:

If E2 is a non-static data member and the type of E1 is “cq1 vq1 X”, and the type of E2 is “cq2 vq2 T”, the expression designates the named member of the object designated by the first expression.

Clearly the object designated by *reinterpret_cast<A*>(&j), i.e. j, has no member, so the behavior is undefined by omission.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
  • There are many situations where parts of the Standard would imply the behavior of some actions in the absence of other parts saying that an overlapping class of actions invoke UB. Transitively applying the equivalence of `&structPtr->firstMember` and `(*firstMemberType)structPtr`, as well as `*&intLvalue` and `intLvalue` would be sufficient to imply how `((structType*)&intObject)->firstMember` should work, so I wouldn't regard such constructs as "undefined by omission". – supercat Jan 02 '19 at 23:37