Don’t abuse of access rights

Posted: September 29, 2011 in Programming Recipes
Tags:

Recently, I’ve been reading Sutter‘s Exceptional C++ Style and I’ve found a couple of interest items I’d like to discuss. They are about (subtle and evil) tricks to get access to class’ internals.

This is the code Sutter uses:


class X {

public:

     X() : private_(1) {  }

     template <class T>
     void f (const T& t) {  }

     int Value() { return private_; }

private:

     int private_;

};

Sutter creates hacks of this code to get direct access to X’s private_ member. He defines some categories of bad guys that violate the programmer’s intent of keeping private_ under the hood.

The first three hacks are non-standards-conforming and non-portable, but they are quite interesting.

Let’s go.

The forger duplicates a forged class definition to make it say what he wants it to say:


class X {

public:
     // instead of including X.h, manually duplicates (illegal) X's definition and add:
     friend ::Hijack(X&);
};

void Hijack(X& x) { x.private_ = 2; } // never trust to your friends!

This is illegal because it violates the One Definition Rule: if a certain type (say X) is defined more than once, the definitions have to be identical. But be careful: if the underlying object data layout is the same, this hack will work on many compilers. Alas.

The second rascal is the pickpocket. He silently changes the meaning of the class definition:


#define private public

#include "X.h"
void Hijack(X& x) { x.private_ = 2; } // free admission!

This sounds like illegal, doesn’t it? Yes, because it is not permitted to #define a reserved word.

Another plotter is the cheat. His modus operandi is to substitute one item when you’re expecting another:


class MyEvilX {

public:

     int notSoPrivate;

};

void f(X& x) {
     (reinterpret_cast<MyEvilX> (x)).notSoPrivate = 2;
}

It is illegal for two reasons: the object layouts are not guaranteed to be the same (but probably will be… ) and the result of a reinterpret_cast  is undefined (but…).

Finally, Sutter explains a fully standards-conforming and portable technique: the language lawyer:

namespace {
	struct Y {};
}

template <>
void X::f(const Y&) {
	private_ = 2;
}

void Test() {
	X x;
	std::cout << x.Value() << std::endl;
	x.f(Y());
	std::cout << x.Value() << std::endl;
}

This artful thief will never be caught because it work is not illegal! In fact it is legal to specialize a member template of any type (besides, the hacker uses a type that resides in his own unnamed namespace, that won’t tromp on anyone else’s specialization).

Sutter’s short chapter demonstrates that a programmer can find a way to subvert the system.

C++’s leak?

No. Simply, protecting against deliberate abuse is effectively impossible. Just say no. Don’t subvert the system. You’re a big boy now!

In conclusion, I’m going to show you another technique to bypass the access mechanism (still taken from Sutter’s book). It’s about granting access:

class FreeAdmission;

typedef int (FreeAdmission::*PMember)(int);

class FreeAdmission {
public:
     PMember Grant() { return &FreeAdmission::ToHide; }

private:
     int ToHide(int i);
};

int main() {

     FreeAdmission freeAdmission;
     PMember p = freeAdmission.Grant();
     int toHideResult = (FreeAdmission.*p)(21);
}

This code emphasizes the definition of a private member of a class: its name can be used only by member and friends of the class in which it is declared. In the example above the private member function of FreeAdmission is executed in the main function, just because a pointer to ToHide was passed out!

I hope this post was useful to look at private members from another point of view!

Advertisements
Comments
  1. GS says:

    If you are modifying header file like this

    class FreeAdmission {
    public:
    PMember Grant() { return &FreeAdmission::ToHide; }

    private:
    int ToHide(int i);
    };

    why not replace `private` with `public` instead ?

    • Marco Arena says:

      The target is to make ToHide public without declaring it public! This trivial example just shows how a private member function can be passed outside the “owner” class, by returning a pointer to that function.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s