33

I just happened to find that a nested private template class can be accessed directly outside the enclosing class using a using directive:

class wrapper
{
private:
    template <typename T>
    class __tklass {};

    class __klass {};
};

template <typename T>
using tklass = wrapper::__tklass<T>;    // Expected error but compiles OK

// using klass = wrapper::__klass;      // "Error: __klass is private"

int main()
{
    tklass<int> v1;                     // Expected error but compiles OK

    // wrapper::__tklass<int> v3;       // "Error: __tklass is private"
    // wrapper::__klass v4;             // "Error: __klass is private"
}

The lines marked "Error: __xxx is private" correctly report an error when uncommented. But the lines with tklass get compiled without any complaint from the compiler.

So why exactly doesn't the compiler flag tklass as error despite wrapper::__tklass being private? Is it by any chance allowed by the standard? If so, wouldn't that be considered a serious access violation?

I tried this on gcc-4.9.2, clang-3.5.0 and visual studio 2013 express. GCC command line:

g++ -std=c++11 -pedantic -Wall -Wextra -Wshadow myfile.cpp
nav
  • 1,645
  • 15
  • 22
  • What compiler are you using? What version of it? – Some programmer dude Jan 15 '15 at 09:30
  • 17
    Oh, and never use leading double underscore, such names are reserved in all scopes. – Some programmer dude Jan 15 '15 at 09:31
  • Nope not working http://ideone.com/T9jHkw – Ankur Jan 15 '15 at 09:32
  • no error in g++ 4.8.1 here (if the "OK,Error" lines are commented out) – M.M Jan 15 '15 at 09:33
  • 8
    I think this is related to the following bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47346, I had a question along the same lines a little while ago; http://stackoverflow.com/questions/17792751/possible-to-access-private-types-in-base-classes-via-template-indirection – Nim Jan 15 '15 at 09:35
  • IIRC this was subject of some DR a while ago – Columbo Jan 15 '15 at 09:48
  • @Nim: Just went through gcc bugzilla and found a lot of similar bugs, all due to templates. But then why does the same issue show up in clang? Is it by any chance built on top of gcc codebase? – nav Jan 15 '15 at 10:36
  • Not overly familiar with clang, could be that they follow a similar pattern to gcc... – Nim Jan 15 '15 at 11:08
  • It works in visual studio 2013 as well :(. Since it works on all 3 compilers, I guess we should rule out compiler bugs. It got to be something the standard allows.. – nav Jan 15 '15 at 12:22
  • 4
    [For Clang, his is LLVM Bug 15914](http://llvm.org/bugs/show_bug.cgi?id=15914). – Casey Jan 15 '15 at 18:51
  • @Casey, The link you mentioned is a fit for answer. This is definitely a bug. The compilers are not handling it properly. – iammilind Jan 19 '15 at 09:17
  • 1
    @JoachimPileborg said [not to use leading underscores and is right](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). FTFY. – nonsensickle Jan 23 '15 at 00:17

2 Answers2

26

This is definitely a compiler bug, and actually one that has been known for quite some time: GCC #47346 (first reported in Jan 2011) and Clang #15914 (first reported May 2013). Your __tklass is clearly private, and the template alias is not marked friend, so this should be a simple access error.

The simplest reproduction is from the Clang example attachment, this version compiles on both gcc 4.9.2 and clang 3.5.0, though should definitely compile on neither:

class A
{
  class B {};
};

template<typename>
using T = A::B;

T<void> t;

Clang is strictly better than GCC on this front however, as this particular bug seems to occur only with template aliases. A "workaround" (if you need such a thing for cases that the compiler allows incorrectly...) would be to revert back to pre-C++11 template aliasing:

template <typename>
struct T {
    using type = A::B;
};

T<void>::type t;

That code correctly fails to compile with clang (error: 'B' is a private member of 'A'), but still compiles fine with gcc.

Barry
  • 286,269
  • 29
  • 621
  • 977
3

Herb Sutter wrote long ago the article, how template member functions may provide a back-door into a class: http://www.gotw.ca/gotw/076.htm (pls. check the case 4: "The Language Lawyer", at the end)

It may give you the answer.

EDIT: I'm curious, what were the reasons for down-voting. I cite the article: "Is this a hole in C++'s access control mechanism, and therefore a hole in C++'s encapsulation? This demonstrates an interesting interaction between two C++ features: The access control model, and the template model. It turns out that member templates appear to implicitly "break encapsulation" in the sense that they effectively provide a portable way to bypass the class access control mechanism."

Seems for me to be a reasonable answer. EDIT END

One could spent plenty of time trying to secure the interfaces by technical means private/protected, etc. My preferred way is to make an agreement among all developers to use well, understood rules complying with least surprise approach. (EDIT: And verify the code against these rules using the code-reviews/reg-exp scripts on regular basis)

"Don't try to find a technical solution for a social problem" B. Stroustrup

Valentin H
  • 7,240
  • 12
  • 61
  • 111
  • 5
    don't worry. For reasons that are not entirely clear to me C++ happen to attract zealots that think to it in religious terms. Anything that is (or simply is perceived as) "imperfect" is understood as blaspheme. My guess is that this absurd view about what is a decent but very imperfect and logically buggy language will heal itself after writing a good amount of real code in the real world. – 6502 Jan 15 '15 at 11:28
  • @6502: Agree! I admit, I used to be like that, before I've started to make money with programming as a freelancer. As long as someone pays for it (parents, employer) you can afford to be cool, a purist or to invent artificial problems. As soon as you have to solve a problem and the client doesn't give a damn on a computer language, then such artificial problems are not affordable any more. P.S.: cool website! so you used to be in demo-scene? Assembly parties? – Valentin H Jan 15 '15 at 12:10
  • 4
    The downvotes are due to the answer being link-only, and the fact that the linked item is about a different issue and does not answer the question. – Casey Jan 15 '15 at 14:56
  • @Casey: I see. As I'm concerned, sometimes I'd wished a link to a guru or a standard-reference rather than a long explanation. In my days (I'm 40 now) the standard learning path of C++ was: Stroustrup, Meyers, Sutter, Elexandrescu. P.S.: Is the answer that wrong? I doubt it. Though the Sutter's example uses a template member function, his statement applies in general for any template member. P.P.S: After spending many many thousands to VS and Qt I'm considering to switch to Python. Such discussions are a big help for that decision. – Valentin H Jan 15 '15 at 18:01
  • 10
    The linked article discusses subverting access control by specializing a template member - it does not apply to this question. The issue in the question is that access control is not applied to the name `__wrapper::__tklass` when referenced inside an alias template. [The fact that the referenced name happens to itself be a template is actually unrelated.](http://coliru.stacked-crooked.com/a/dced7a56390facaa) – Casey Jan 15 '15 at 18:22
  • The possible loophole seems to be created because of `using` keyword in the question. The link you have mentioned seems older than that. (I haven't down-voted though) – iammilind Jan 19 '15 at 09:14
  • @Casey: OK, I agree. Thanks for coliru-link! – Valentin H Jan 19 '15 at 17:36
  • 3
    Well, I just downvoted, because that hole is not the same as the one the OP is talking about. What more, the content of your answer (what you claim to be the problem) is included only in the linked document, and isn't here: that makes it a bad answer (the linked target may change in the future, rendering the answer even less useful), as well as incorrect (the linked answer doesn't answer the OP's problem). That is two reasons to downvote. A third reason to downvote is responding to downvotes with an "**edit**: why am I being downvoted". 4th, answer poorly formatted. – Yakk - Adam Nevraumont Jan 22 '15 at 19:31