13

Our infamous litb has an interesting article on how to circumvent the access check.

It is fully demonstrated by this simple code:

#include <iostream>

template<typename Tag, typename Tag::type M>
struct Rob { 
  friend typename Tag::type get(Tag) {
    return M;
  }
};

// use
struct A {
  A(int a):a(a) { }
private:
  int a;
};

// tag used to access A::a
struct A_f { 
  typedef int A::*type;
  friend type get(A_f);
};

template struct Rob<A_f, &A::a>;

int main() {
  A a(42);
  std::cout << "proof: " << a.*get(A_f()) << std::endl;
}

Which compiles and runs (output 42) with gcc 4.3.4, gcc 4.5.1, gcc 4.7.0 (see user1131467's comment) and compiles with Clang 3.0 and Comeau C/C++ 4.3.10.1 in C++03 strict mode and MSVC 2005.

I was asked by Luchian on this answer in which I used it to justify that it was actually legal. I agree with Luchian that it is weird, however both Clang and Comeau are close contenders for the most "Standard" compilers available (much more so than MSVC by default)...

And I could not find anything in the drafts of the Standards I have available (n3337 being the last version I got my hands on).

So... can anyone actually justifies that it is legal or not ?

Community
  • 1
  • 1
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722

2 Answers2

13

Yes, it's legal. The relevant text is at §14.7.2/12, talking about explicit template instantiation:

12 The usual access checking rules do not apply to names used to specify explicit instantiations. [ Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible. — end note ]

Emhpasis mine.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
5

The code is clearly illegal (and requires a compile time diagnostic). In the line:

template struct Rob<A_f, &A::a>;

the expression A::a accesses a private member of A.

The standard is very clear about this: “Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions.“ (§11/4, emphasis added). Since a is a private name in A, any reference to it outside of A is illegal.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 3
    It is actually not illegal, an exception is added later for explicit template instantiations. The "all" there is obviously misleading, it's "all, unless otherwise specified". I won't downvote because it's quite unintuitive. – GManNickG Mar 28 '12 at 12:37
  • @GManNickG Actually, it's not clear, and I think a DR is in order. In the standard, "all" means "all", not "all, unless otherwise specified", and the context in §14.7.2 can allow other interpretations (although they aren't very natural). This looks like a contradiction, which means that a DR is in order. – James Kanze Mar 28 '12 at 15:18
  • You're right, there's no need for that qualification to be there. – GManNickG Mar 28 '12 at 18:59
  • 2
    While you are correct (IMO) to point out this contradiction in the spec, that does not mean that "The code is clearly illegal.". It means, like for any serious legalese "if any rule of this law turns out to be defective or illegal, it is to be replaced by a rule that fits the intended purpose as good as possible." (severability clause ). You cannot take a rule and based on a contradiction interpret it contradictory to the committee's intent. – Johannes Schaub - litb Mar 28 '12 at 19:07
  • You may aswell iterate over the issues of the current-issues page of wg21 and reject literally *any* program because of not having applied reasonable fixes of defective rules in the Standard. – Johannes Schaub - litb Mar 28 '12 at 19:08
  • @JamesKanze: I was planning to submit a DR asking for cross-referencing. If you submit one for the contradiction, please let me know as I don't want to submit a duplicate. – Matthieu M. Mar 28 '12 at 19:20
  • @MatthieuM. I think it may mean to say something different than what we thought it means. "name" has a dual meaning in the spec. One meaning is the identifier that is declared into a declarative region. That identifier (or operator-funtion-id, literal-operator-id, etc) is thereafter called "name". For example, a member declaration declares a member-name of its class. A class declaration declares a class-name in the surrounding scope and into itself (injected-class-name). The other meaning of "name" is an identifier, operator-function-id etc.. that appears in expressions or declarations. – Johannes Schaub - litb Mar 28 '12 at 19:43
  • Now note what it precisely says: "Access control is applied uniformly to all names, *whether the names are referred to from declarations or expressions.*". If it talked about the second meaning of name (we until now thought that it does), then "... are referred to from declarations or expressions" would not make any sense. You cannot refer to a declaration or expression from itself! Hence it talks about the first meaning of "name". For example, a member's name may be referred to by a id-expression in a class-member access expression. – Johannes Schaub - litb Mar 28 '12 at 19:47
  • Actually, when read in context of 11/4 it seems to be very clear that it talks about meaning #1 of "name". – Johannes Schaub - litb Mar 28 '12 at 20:01
  • @JohannesSchaub-litb: Ah thanks... I found those "term of the art" difficult to spot, but if they overload them... Well, in this case this would not be a contradiction, but it would still be good (I think) to cross-reference the section, for those of us poor readers trying to figure out the rules. – Matthieu M. Mar 29 '12 at 06:09
  • @JohannesSchaub-litb When I wrote "clearly illegal", I wasn't aware of the contradicting text in §14.7.2/12. Knowing this, I'd probably write that it is "illegal under the most reasonable interpretation of the standard, but the standard needs clarification here." The intent of §11/4 is obvious; the intent of §14.7.2/12 is less clear. – James Kanze Mar 29 '12 at 07:30
  • @james as the author of class A, how would you otherwise write the explicit instantiation without violating access? – Johannes Schaub - litb Mar 29 '12 at 08:27