Returning a pointer-to-member function under a certain condition is not work

I found that returning a pointer-to-member function under a certain condition, is not work as I expected.

It happens on a very specific situation: on armv7, with compiler optimization level -Os.

Along with other platforms like arm64, simulators, x86_64, and other optim-level from -O0 to -Ofast, the code is work.

Tested on Xcode 7.3, 7.3.1, and 8 beta.

(I don't remember the exact Xcode version, but anyway on older Xcode the code works well.)


The code is somewhat complex, although I've tried my best to narrow down it to find and reproduce the problem.


#include <iostream>

class Base
{
public:
    Base() {}
    virtual ~Base() {}
};

#define ToFuncPtr(FN) static_cast<FuncPtr>(&FN)
typedef void (Base::*FuncPtr)(int arg);

class Interface
{
public:
    virtual ~Interface() {}
    virtual FuncPtr getFuncPtr() = 0;
};

class Derived
: public Base
, public Interface
{
public:
    Derived() {}
    virtual ~Derived() {}

    void test()
    {
        Interface * pI = dynamic_cast<Interface *>(this);
        FuncPtr f = pI->getFuncPtr();

        std::cout << "returned " << *((ptrdiff_t*)&f) << std::endl;
        (this->*f)(1);
    }

    FuncPtr getFuncPtr() override
    {
        std::cout << "Do something to prevent this function from be implicitly inlined.\n";

        FuncPtr pFn = ToFuncPtr(Derived::func);
        std::cout << "want to return " << *((ptrdiff_t*)&pFn) << std::endl;

        return ToFuncPtr(Derived::func);
    }

protected:
    void func(int arg)
    {
        std::cout << "func " << arg << std::endl;
    }
};


And somewhere in the code path, I wrote a code like :


    Derived * pD = new Derived;
    pD->test();
    delete pD;


then run the code, will crash at line 34.


It's interested to see that

  • If the function (L:37) is inlined, then the problem is gone.

    eg) Add inline in front of L:37.

  • It happens when the dynamic_casted (L:30) pointer is different from this pointer.

    eg) Remove L.7, L.16.

  • If the return type is other than a pointer to member function, it seems that work nicely.

    eg) Use void *.


I can't find the exact reason. Is the problem related to some kind of broken memory layout with multiple virtual inheritance?

Actually I waited over 1 month with a feeling of expectancy that Xcode/LLVM update will solve this phenomenon,

but it doesn't, so I posted here to ask the solution. Anyone can help please?

Returning a pointer-to-member function under a certain condition is not work
 
 
Q