0

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;
}
Rafa
  • 3,219
  • 4
  • 38
  • 70
  • Then you want an answer that depends on the implementation. If that is OK, I will give you one that works for MSVC. – Lingxi Apr 26 '15 at 02:11
  • You either make those functions `public`, or declare `extractMultAdd()` as a `friend` function. – πάντα ῥεῖ Apr 26 '15 at 02:12
  • @πάνταῥεῖ The OP said he/she is only allowed to modify `extractMultAdd`. – Lingxi Apr 26 '15 at 02:13
  • @Lingxi if the MSVC gets the basic idea down then I may be able to work with that – Rafa Apr 26 '15 at 02:26
  • @ralphie9224 It seems that to have `this` pointer correctly passed to the virtual functions, you have to use the specific register `ECX`. Not sure how to do this without inline assembly. – Lingxi Apr 26 '15 at 02:46
  • @Lingxi a solution like that will do as well if it falls within the boundaries of what was given. – Rafa Apr 26 '15 at 02:48
  • *You don't* use virtual tables to access virtual functions. You just call them. – user253751 Apr 26 '15 at 03:22
  • @immibis if they are public. I was assuming given the context of the problem that we would use them since they are private and can't be called. – Rafa Apr 26 '15 at 04:15
  • @ralphie9224 Is this for an assignment to understand or something? Normally, the correct way to call a private function from outside the class is also "don't". – user253751 Apr 26 '15 at 04:29

2 Answers2

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);
}
Lingxi
  • 14,579
  • 2
  • 37
  • 93
  • In the first example, shouldn't the add and multiply be `virtual`? (Ah, no, you are replicating the `vtable`, right? – Mats Petersson Apr 26 '15 at 08:29
  • @MatsPetersson By deriving from `MultAdd`, they are virtual by default. Maybe you overlooked `MultAdd` in `struct MultAddCracker: MultAdd` :-) – Lingxi Apr 26 '15 at 08:33
0

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 :)
Community
  • 1
  • 1
namezero
  • 2,203
  • 3
  • 24
  • 37