Created
October 29, 2017 15:26
-
-
Save WorldSEnder/25ecf91236ec04a89ea3bdc9c1056142 to your computer and use it in GitHub Desktop.
C++ private member access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
class Foo { | |
int bar = 0; | |
int foobar = 999; | |
static inline int zip; | |
public: | |
void print() { | |
std::cout << "Bar: " << bar << std::endl; | |
std::cout << "Zip: " << zip << std::endl; | |
} | |
}; | |
// "Attacker" code | |
// Descriminator struct - provides a unique linkage name, and the target type | |
struct FooBarValue { using type = int (Foo::*); }; | |
// Explicit instantiation, where we are allowed to use the private member | |
template class public_cast<FooBarValue, &Foo::bar>; | |
// We are only allowed to use it in the explicit instantiation, thus | |
// we need a way to extract it without having to reuse the private member | |
using accessBar = public_access<FooBarValue>; | |
// Compact form (also showing static variables) | |
struct FooZipValue { using type = int &; }; | |
template class public_cast<FooZipValue, Foo::zip>; | |
using accessZip = public_access<FooZipValue>; | |
// Can't reuse FooBarValue | |
// template class public_cast<FooBarValue, &Foo::foobar>; | |
int main(int argc, char** argv) | |
{ | |
Foo foo; | |
foo.print(); | |
// Look mom, we can access private members of Foo | |
foo.*(accessBar::unlock()) = 42; | |
accessZip::unlock() = 42; | |
foo.print(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <memory> | |
using std::reference_wrapper; | |
/// | |
template<typename T> | |
struct _internalize; | |
template<typename T> | |
struct _internalize<T&> { | |
using type = reference_wrapper<T>; | |
}; | |
template<typename T> | |
struct _internalize<T*> { | |
using type = T*; | |
}; | |
template<typename T, typename M> | |
struct _internalize<M T::*> { | |
using type = M T::*; | |
}; | |
template<typename T> | |
using internalize_t = typename _internalize<T>::type; | |
/// | |
template<typename Tag, typename Tag::type P> | |
class public_cast; | |
template<typename Tag> | |
class public_access { | |
using public_type = typename Tag::type; | |
using internal_type = internalize_t<public_type>; | |
static inline internal_type value; | |
static public_type init(public_type p) { | |
static bool wasCalled = false; | |
if(wasCalled) { | |
throw "Double initialization forbidden"; | |
} | |
public_access<Tag>::value = p; | |
wasCalled = true; | |
return p; | |
} | |
template<class T, typename T::type P> | |
friend class public_cast; | |
public: | |
static public_type unlock() { | |
return value; | |
} | |
}; | |
/// | |
template<typename Tag, typename Tag::type P> | |
class public_cast { | |
using internal_type = typename Tag::type; | |
static const inline internal_type value = public_access<Tag>::init(P); | |
friend constexpr internal_type enforce_once(Tag) { | |
return P; | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment