[Exceptional C++ Style] [Exception C++ Style] Item 15 - Uses and Abuses of Access Rights

James Gunn gunnware at yahoo.com
Tue Dec 14 06:19:59 EST 2004


This item discusses one JG question and two Guru
questions.

JG Question

1. What code can access the following parts of a
class?

a) public
b) protected
c) private

Guru Questions

2. Consider the following header file:

// File x.h
//
class X 
{
public:
    X() : private_(1) {/*...*/}

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

    int Value() { return private_; }

    //...

private:
    int private_;
};

Demonstrate:

  a) a non-standards-conforming and non-portable hack;
and
  b) a fully standards-conforming and portable
technique

for any code to get direct access to this class's
private_ member.

3. Is this a hole in C++'s access control mechanism,
and therefore a hole in C++'s encapsulation?

Solution

1.

Sutter states the answers for what code can access
public, protected and private parts of a class with
private access being the interesting 

one. He goes on to state that for private members the
usual answer is only member functions and friends can
access them. Sutter then 

discusses a special case where access to a class's
private members can be legally subverted. 

2.

Sutter starts this answer by discussing three
non-standards-conforming and non-portable hacks:

The Forger duplicates a class definition to make it
say what he wants it to say. The Forger's hack is
illegal as it breaks the One Definition 

Rule (ODR). Sutter states that this will work on most
compilers because the underlying data layout will
usually be the same.

The Pickpocket attempts to change the meaning of the
class definition by redefining private as public:

#define private public

However, the above is illegal as it attempts to
redefine a keyword. It also breaks the ODR and
therefore the same thing applies as was stated 

for The Forger.

The Cheat attempts to substitute one item when your
expecting another. For example:

class BaitAndSwitch
{
public:
    int notSoPrivate;
};

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

Sutter states that the example, above, is illegal for
two reasons:
The object layouts of X and BaitAndSwitch are not
guaranteed to be the same, although they probably
always will be.The results of the 

reinterpret_cast are undefined, although most
compilers will let you try to use the resulting
reference in the way The Cheat intended.

At this point Sutter gives a great desciption of
criminals and hackers before moving on to show a fully
standards-conforming and portable 

technique to subvert the access to private members.

Sutter states that The Langugage Lawyer is a
dishonest, toothy-smiled criminal :-)

The following example is given for the legal weasel:

namespace 
{
    struct Y{};
}

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

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

The above is completely legal because, as Sutter
informs us, it exploits the fact that X has a member
template and is fully 

standards-conforming and is guaranteed by the standard
to work as expected. There are two reasons for this:

1. It's legal to specialise a member template on any
type.
   The only room for error would be if you tried to
specialise it on the same type twice in different
ways, which would violate the ODR, but 

we get round that because:

2. The code uses a type that's guaranteed to be
unique, because it's in the hacker's own unnamed
namespace. Therefore it's guaranteed to be 

legal and won't stomp on anyone else's specialisation.

Don't Subvert

Sutter then answers the final question:

3. Is this a hole in C++'s access control mechanism,
and therefore a hole in C++'s encapsulation?

Sutter starts his answer by stating that a portable
way to bypass the class's access control mechanism,
and implicitly "break encapsulation" 

is provided by member templates. Following on, he
discusses that the issue is about protecting against
accidental misuse as opposed to 

protecting against deliberate abuse. The examples in
this item clearly show that if someone wants to they
can subvert the system.

Finally, the real answer to the issue is to not
subvert the access control system. I agree with Sutter
at this point that subverting the 

access control system should be a one-warning offence
if it's used in production code.

Guideline:

Never subvert the language. For example, never attempt
to break encapsulation by copying a class definition
and adding a friend declaration 

or by providing a local instantiation of a template
member function.


		
__________________________________ 
Do you Yahoo!? 
Send a seasonal email greeting and help others. Do good. 
http://celebrity.mail.yahoo.com



More information about the Effective-cpp mailing list