Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can one access private member functions through casting to layout-compatible types?

From the discussion of this question How is access for private variables implemented in C++ under the hood? I posed a variation: instead of accessing a private data member, can one call private member functions through casting and relying on layout-compatibility?

Some code (inspired by Herb Sutter's column Uses and Abuses of Access Rights )

#include <iostream>

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

private: 
  int Value() { return private_; }
  int private_; 
};

// Nasty attempt to simulate the object layout
// (cross your fingers and toes).
//
class BaitAndSwitch
    // hopefully has the same data layout as X
{   // so we can pass him off as one
public:
  int Value() { return private_; }
private:
  int private_;
};

int f( X& x )
{
  // evil laughter here
  return (reinterpret_cast<BaitAndSwitch&>(x)).Value();
}

int main()
{
    X x;
    std::cout << f(x) << "\n"; // prints 0, not 1
    return 0;
}; 

Note: this works (at least on Ideone)! Is there any way the new C++11 Standard gives a guaranteed or at least an implementation-defined way to circumvent the access control by relying on layout-compatibility and reinterpret_cast / static_cast?

EDIT1: output on Ideone

EDIT2: In Sutter's column he lists two reasons why the above code is not guaranteed to work (although it works in practice)

a) The object layouts of X and BaitAndSwitch are not guaranteed to be the same, although in practice they probably always will be.

b) The results of the reinterpret_cast are undefined, although most compilers will let you try to use the resulting reference in the way the hacker intended.

Does the new C++11 Standard now provide these layout / reinterpret_cast guarantees?

like image 399
TemplateRex Avatar asked Jul 15 '12 18:07

TemplateRex


People also ask

How do you access private member functions?

How to access a private member function of a class? Explanation: Even the private member functions can be called outside the class. This is possible if address of the function is known. We can use the address to call the function outside the class.

Can member functions access private members?

The private MembersA private member variable or function cannot be accessed, or even viewed from outside the class. Only the class and friend functions can access private members.

Can we access private data members of a class without using a member or a friend function in C ++?

In C++, a friend function or friend class can also access private data members. So, is it possible to access private members outside a class without friend? Yes, it is possible using pointers.

Can constructor access private members?

So the private variable cannot been seen and accessed from outside the scope of the constructor. But inside it you can alter it, log it, pass it to a function, reassingn it like you want.


1 Answers

Yes, you could create a type that uses the same layout as the type you're trying to pilfer from, then reinterpret_cast from that type to your layout compatible type. But this is only protected by the standard if both the source and destination types are standard layout types (and of course, it only actually works if their layouts are the same). So if the source has virtual functions, you're screwed.

This seems to satisfy both of Sutter's issues here. The rules of standard layout ensure that two types that are both standard layout that define the same members in the same order are layout-compatible (section 9.2, paragraph 17):

Two standard-layout struct (Clause 9) types are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in declaration order) have layout-compatible types (3.9).

And the rules for reinterpret_cast specify the meaning of the conversion between two standard layout types (section 5.2.10, paragraph 7):

An object pointer can be explicitly converted to an object pointer of a different type. When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void.

like image 104
Nicol Bolas Avatar answered Sep 30 '22 04:09

Nicol Bolas