Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a C++ member function pointer: this-pointer gets corrupted

I need to convert some member function pointers to void* pointers (because I need to push them to the Lua stack, but the problem is not Lua related).

I do this using a union. But when I convert the member function pointers to a void* and back again and then try to call the pointer with an instance of the class, the this pointer gets corrupted. Strangly, this problem doesn't happen, if I convert the void* pointer back into a C-style function pointer with a pointer to the class as it's first parameter.

Here is piece of code that demonstrates the problem:

#include <iostream>
using namespace std;

class test
{
    int a;

    public:
        void tellSomething ()
        {
            cout << "this: " << this << endl;
            cout << "referencing member variable..." << endl;
            cout << a << endl;
        }
};

int main ()
{
    union
    {
        void *ptr;
        void (test::*func) ();
    } conv1, conv2;

    union
    {
        void *ptr;
        void (*func) (test*);
    } conv3;

    test &t = *new test ();

    cout << "created instance: " << (void*) &t << endl;

    // assign the member function pointer to the first union
    conv1.func = &test::tellSomething;

    // copy the void* pointers
    conv2.ptr = conv3.ptr = conv1.ptr;

    // call without conversion
    void (test::*func1) () = conv1.func;
    (t.*func1) (); // --> works

    // call with C style function pointer invocation
    void (*func3) (test*) = conv3.func;
    (*func3) (&t); // --> works (although obviously the wrong type of pointer)

    // call with C++ style member function pointer invocation
    void (test::*func2) () = conv2.func;
    (t.*func2) (); // `this' is the wrong pointer; program will crash in the member function

    return 0;
}

That is the output:

created instance: 0x1ff6010
this: 0x1ff6010
referencing member variable...
0
this: 0x1ff6010
referencing member variable...
0
this: 0x10200600f
referencing member variable...
zsh: segmentation fault (core dumped)  ./a.out

Is this a bug in the compiler (GCC)? I know that this conversion between void* and (member) function pointers is not standard compliant, but the odd thing is, that it works, when converting the void* to a C style function pointer.

like image 544
Alfred Krohmer Avatar asked Jun 11 '12 09:06

Alfred Krohmer


People also ask

Can we call member function using this pointer?

You can use pointers to member functions in the same manner as pointers to functions. You can compare pointers to member functions, assign values to them, and use them to call member functions.

What is the problem of function pointer?

There are two main issues with function pointers: Function pointer casts can cause function pointer calls to fail. This may be related to a function pointer cast problem as implicit declarations may have a different type than how you call them.

What is the type of this pointer in its member function?

The this pointer is a pointer accessible only within the nonstatic member functions of a class , struct , or union type. It points to the object for which the member function is called. Static member functions don't have a this pointer.

Which function Cannot be passed a this pointer?

A static member function does not have a this pointer. The type of the this pointer for a member function of a class type X , is X* const .


2 Answers

Add these two lines to your code and the answer will be clear:

cout << "sizeof(void*)=" << sizeof(conv1.ptr) << endl;
cout << "sizeof(test::*)=" << sizeof(conv1.func) << endl;

The reason is simple. Consider:

class Base1
{
 public:
 int x;
 void Foo();
 Base1();
};

class Base2
{
 public:
 float j;
 void Bar();
 Base2();
};

class Derived : public Base1, public Base2
{
 Derived();
};

When you call Foo on a Derived, the this pointer must point to Base1::x. But when you call Bar on a Derived, the this pointer must point to Base2::j! So a pointer to a member function must include both the address of the function and an "adjustor" to correct the this pointer to point to an instance of the correct type of class that the function expects as the this pointer.

You are losing the adjuster, causing the this pointer to be adjusted randomly.

like image 57
David Schwartz Avatar answered Nov 12 '22 22:11

David Schwartz


Weirdly enough, here (under VS2005), the 1st and 3rd calls works fine but the 2nd (with conv3) fails with the this being corrupted.

like image 45
Clément Avatar answered Nov 12 '22 21:11

Clément