Saturday, July 3, 2010

Access to private members. That's easy!

So, always thought that it's impossible without undefined behavior to access private members of arbitrary classes without being friend.

Today I noticed I've been horribly wrong, after reading some insightful commit to the clang compiler, that enabled it to allow explicit instantiation to disregard accessibilities, as per the Standard. This enables us to access private members of others. As an experiment, I created some class templates

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

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;
};

template<typename Tag, typename Tag::type p>
typename rob<Tag, p>::filler rob<Tag, p>::filler_obj;

So, how is it used? Let's have an example

struct A {
private:
  void f() {
    std::cout << "proof!" << std::endl;
  }
};

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

Ah, that's all to expose poor A's "f" member. Now anyone can use them using the member pointer snytax, as does the main function below

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

Of course, as Herb Sutter told us, don't do these things in real code.