J22o
J22o

Reputation: 147

ESP was not properly saved across a function call when using function pointers

I am trying to create a program which saves the function pointer of a member function to an array. The program then takes the function pointer from that array and calls the function said pointer points to. This works as long as the member function used does not have any arguments. When I give it arguments the following error occurs in Visual Studio 2017:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

My code is:

typedef uint8_t byte;

template<typename T>
class Test
{
public:
    void FuncTest(byte* data)
    {
        cout << (T)(0.0625f) << endl;
    }
};

typedef Test<float> fTest;
typedef Test<long long> lTest;

int main()
{
    byte data[1024];

    {
        void (fTest::*ffp)(byte*) = &fTest::FuncTest;
        //void (lTest::*lfp)(byte*) = &lTest::FuncTest;

        printf("%p\n", ffp);

        memcpy(&data[0], (int64*)&ffp, sizeof(int64));
    }

    {
        int64 pData;

        memcpy(&pData, &data[0], sizeof(int64));

        void(*func_pointer)(byte*) = (void(*) (byte*))(pData);

        printf("%p\n", pData);

        func_pointer(nullptr);
    }
}

If anyone could help, it would be greatly appreciated.

Upvotes: 0

Views: 1663

Answers (1)

Alan Birtles
Alan Birtles

Reputation: 36488

Ignoring the storage in an array your code is essentially:

void (Test::*ffp)(byte*) = &fTest::FuncTest;
void* pData = (void*)ffp;
void(*func_pointer)(byte*) = (void(*) (byte*))(pData);
func_pointer(nullptr);

The type of ffp is essentially (although not exactly due to differing calling conventions) void (fTest*, byte*) which doesn't match the type of func_pointer.

The solution to this is to use std::function with with either std::bind or lambdas to convert the function signatures. e.g.:

std::vector<std::function<void(byte*)>> functions;
fTest test;
functions.push_back([=](byte* data){ test.FuncTest(data); });
functions.front()(nullptr);

Upvotes: 1

Related Questions