简体   繁体   中英

Accessing private virtual functions within same class

I was asked, using this code and only writing in the extractMultAdd() function, to return variable.x variable.y variable.add() and variable.multiply . I understand that the basic concept of virtual tables and when they are created, but despite my best efforts, I'm not quite sure how to leverage them to access the private virtual functions. Any help would be appreciated.

#include <cstdio>
#include <iostream>
class MultAdd
{

private:
    int x;
    int y;
    virtual int add()   //virtual fuction so vtable created for Thing class
    {
            return x+y;
    }
    virtual int multiply()
    {
            return x*y;
    }
public:
    MultAdd(){
            x = 2;
            y = 10;
    }
};

int extractMultAdd(void* math)
{
    return 0;
}

int main()
{
    MultAdd variable;
    printf("%d\n", extractMultAdd(&variable));
    return 0;
}

I give you two versions to choose. They do not follow the standard, and are by no means portable, but both work on MSVC 2013, GCC 4.9, and clang 3.5 as I test it. The second version is relatively safer and more portable than the first one. In fact, I expect it to be rather robust.

Version 1:

#include <iostream>

class MultAdd {
private:
  int x;
  int y;
  virtual int add() { return x + y; }
  virtual int multiply() { return x * y; }
public:
  MultAdd() {
    x = 2;
    y = 10;
  }
};

struct MultAddCracker: MultAdd {
  int add();
  int multiply();
};

void extractMultAdd(MultAdd& v) {
  char* p = (char*)&v;
  std::cout << *(int*)(p + sizeof(void*)) << '\n';
  std::cout << *(int*)(p + sizeof(void*) + sizeof(int)) << '\n';
  MultAddCracker* pcracker = (MultAddCracker*)&v;
  std::cout << pcracker->add() << '\n';
  std::cout << pcracker->multiply() << '\n';
}

int main() {
  MultAdd v;
  extractMultAdd(v);
}

Version 2:

#include <iostream>

class MultAdd {
private:
  int x;
  int y;
  virtual int add() { return x + y; }
  virtual int multiply() { return x * y; }
public:
  MultAdd() {
    x = 2;
    y = 10;
  }
};

struct MultAddCracker {
  int x;
  int y;
  virtual int add();
  virtual int multiply();
};

void extractMultAdd(MultAdd& v) {
  MultAddCracker& w = (MultAddCracker&)v;
  std::cout << w.x << '\n';
  std::cout << w.y << '\n';
  std::cout << w.add() << '\n';
  std::cout << w.multiply() << '\n';
}

int main() {
  MultAdd v;
  extractMultAdd(v);
}

Well, if you're looking for a portable way, I could offer the following, which a C++ compiler must support . It is discussed further here . In short, it leverages the fact that access checking rules are bypassed in explicit template instantiations as per 14.7.2p8:

14.7.2p8 The usual access checking rules do not apply to names used to specify explicit instantiations. [Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects which would normally not be accessible and the template may be a member template or member function which would not normally be accessible.]

It does almost what you want to do; the only caveat with this is that template declarations cannot be at the function scope as per 14.2:

A template declaration can appear only as a namespace or class scope declaration

This might break the spirit of the question though the way it is phrased. I don't know of any way to weasle the template structs into the function scope, but if there is a similar trick, this could do 100% what you want.

////////////////////////////////////////////////////////////////////////////////////////
//// The template classes can unfortunately not be declared inside extractMultAdd ()
////////////////////////////////////////////////////////////////////////////////////////

#define ROB_PRIVATE_MEMBER_INST(CLASS, TYPE, MEMBER)    \
template<typename T>                                    \
struct CLASS##_##MEMBER##_rob_tag {                     \
  typedef T CLASS::*type;                               \
  friend type get(CLASS##_##MEMBER##_rob_tag);          \
};                                                      \
template<typename Tag, typename Tag::type M>            \
struct CLASS##_##MEMBER##_rob_private                   \
{                                                       \
    friend typename Tag::type get(Tag) { return M; }    \
};                                                      \
template struct CLASS##_##MEMBER##_rob_private<         \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>;     \

#define ROB_PRIVATE_MEMBER_INST_FN(CLASS, TYPE, MEMBER) \
template<typename T>                                    \
struct CLASS##_##MEMBER##_rob_tag {                     \
  typedef T type;                                       \
  friend type get(CLASS##_##MEMBER##_rob_tag);          \
};                                                      \
template<typename Tag, typename Tag::type M>            \
struct CLASS##_##MEMBER##_rob_private                   \
{                                                       \
    friend typename Tag::type get(Tag) { return M; }    \
};                                                      \
template struct CLASS##_##MEMBER##_rob_private<         \
CLASS##_##MEMBER##_rob_tag<TYPE> , &CLASS::MEMBER>;     \

#define ROB_PRIVATE_MEMBER_ACCESS(CLASS, INSTANCE, TYPE, MEMBER) \
    (INSTANCE.*get(CLASS##_##MEMBER##_rob_tag<TYPE>()))          \

////////////////////////////////////////////////////////////////////////////////////////
//// Actually use the macros
////////////////////////////////////////////////////////////////////////////////////////

ROB_PRIVATE_MEMBER_INST(MultAdd, int, x);
ROB_PRIVATE_MEMBER_INST(MultAdd, int, y);
ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(MultAdd::*)(), add);
ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(MultAdd::*)(), multiply);

////////////////////////////////////////////////////////////////////////////////////////

//ROB_PRIVATE_MEMBER_INST_FN(MultAdd, int(__thiscall *)(), add);
int extractMultAdd(void* math)
{
    // No need to pass as void*
    MultAdd *pMA(reinterpret_cast<MultAdd*>(math));

    // ROB_PRIVATE_MEMBER_INST(MultAdd, int, x); // Note that unfortunately this isn't possible

    // The 4 values, retrieved in a portable way
    int robbed_x = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int, x);
    int robbed_y = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int, y);
    int robbed_add = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int(MultAdd::*)(), add)();      // Note we're calling function with ()
    int robbed_mul = ROB_PRIVATE_MEMBER_ACCESS(MultAdd, *pMA, int(MultAdd::*)(), multiply)(); // Note we're calling function with ()


    return 0;
}

Ignore the friend declaration warnings and scroll to output:

Run example

Of course "only writing in the extractMultAdd() function" might leave some room for this semantic trickery:

int extractMultAdd(void* math)
{
    return extractMultAdd_impl(math);
}

// structs

int extractMultAdd_impl(void* math)
{
    // original code ...
} // <== Original brace :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM