Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this template code allowed to violate C++'s private access specifier?

In the following code, which I found here:

http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html

it appears to step right across C++'s private access specifier. It allows me to call private functions and read/write private data members.

Searching SO found this related issue which was a confirmed GCC compiler bug

c++ template seems to break access specifiers

So naturally I tried using that guy's test code. What was interesting is that my gcc 4.5 compiler indeed has that bug ( it accepts the code and prints the private info ) despite it being reported in gcc 4.3 and me using 4.5.

Anyway, I then went to the Comeau online compiler, which some of the responses to the thread said they tried. I confirmed Comeau does not accept the code from that question, but it does accept my code below.

So ultimately my question is, have I stumbled across a bug in GCC and Comeau's C++ compiler ? Does this compile with VC++ ? If it's not a bug, can someone explain how it works ? I get that it's able to declare a static member function pointer and point it to the private section, but how is it accomplishing this ?

Misc notes: Yes, I know that actually doing this is Very Very Bad. This will also work if you declare a member data ptr and allow you to read/write to private data. Some of the weird comments were from me trying to label it for understanding. I did not conjure up this code and I take no credit for it. I just found it on google. I may not have enough reputation points to reply to comments but I will read everything you say. Thanks for taking a look.

#include <iostream>

using namespace std;


//--------------------------------------------
//
template<typename Tag>
struct result 
{
  /* export it ... */
  typedef typename Tag::type type;

  static type ptr;
};


// allocate space for the static member
template<typename Tag>
typename result<Tag>::type result<Tag>::ptr;

//--------------------------------------------

template<typename Tag, typename Tag::type p>
struct rob : result<Tag> 
{
  /* fill it ... */
  struct filler 
  {
      filler() { result<Tag>::ptr = p; }
  };

  static filler filler_obj;
};

// allocate space for the static member
template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;
//--------------------------------------------


struct A 
{
  private:

    void f() 
    {   
        cout << "hey, don't touch me I'm private!" << endl;
    }
};

struct Af  
{ 
    typedef void(A::*type)(); 
};
template class rob<Af, &A::f>;



int main()
{
    A a;
    (a.*result<Af>::ptr)();
}

~> ./a.out hey, don't touch me I'm private!

~> g++ --version g++ (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch revision 160292] Copyright (C) 2010 Free Software Foundation, Inc.

like image 579
Timmah Avatar asked Nov 23 '11 21:11

Timmah


1 Answers

As a Loki Astari said, public and private are just semantics for the compiler so it can give you warnings that you're not using your code the way you intended.

I don't play with method pointers much (if at all), so I haven't the patience to figure this out fully. But it's no different to doing a mixture of the following. That is to say, using pointer logic to point at whatever bit of memory you want and casting functions and methods and misusing them.

#include <iostream>

using namespace std;

struct A 
{
  public:
    void g()
    {
      cout << "value of i is " << this->i << endl;
    }
    void setJ(int newJ) {
      j = newJ;
    }
    int i;
  private:
    int j;
};

int main() {

    A a;
    a.i = 5;
    a.setJ(10);

    // accessing private field j
    cout << "value of j is " << *((&a.i)+1) << endl;

    // creating a pointer to method g    
    void(A::*method)() = &A::g;

    // changing it to be a function pointer
    void(*function)(A*) = (void(*)(A*)) method;

    // using function pointer to call A::g  
    function(&a);  

    return 0;
}
like image 185
Dunes Avatar answered Sep 24 '22 18:09

Dunes