MinGW 4.7.0 to 4.7.2 bug: Invalid "this" pointer in member functions when using mixed virtual and non-virtual multiple inheritance

StackOverflow https://stackoverflow.com/questions/19073970

Question

I have code with inheritance that looks like this:

        B
       / \
      /   \
     /     \
    BI      D
(template) /
      \   /
       \ /
        DI
    (template)

[B]ase and [D]erived are interfaces that both contain a static method create(), which returns an instance of the respective implementation, BaseImpl or DerivedImpl. The implementations are templates, and the factory methods choose how to instantiate them at runtime. The code below is a working example of my program's logic.

The problem is, in my real code, Base methods get a faulty this pointer and inevitably crash. I have examined the assembly code right before the call to one of the methods, which takes no arguments, in both real and example code, and found that it differs:

Working (example) code

call   <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const>
mov    (%eax),%edx
add    $0x8,%edx
mov    (%edx),%edx
mov    %eax,%ecx
call   *%edx

The above translates to a base->method() call, where base is a std::unique_ptr<Base>. For those that don't know, the calling convention of class methods can be a __thiscall, which it in this case is. That means that this isn't passed on the stack, but is stored in ecx. The code above simply stores this into ecx, and then locates method(), stores its address into edx, and calls it. Everything works as it should.

Faulty (real) code

call   <std::unique_ptr<Base, std::default_delete<Base> >::operator->() const>
mov    (%eax),%edx
add    $0x18,%edx
mov    (%edx),%ebx
lea    -0x24(%ebp),%edx
mov    %eax,(%esp)
movl   $0x9,-0x9c(%ebp)
mov    %edx,%ecx
call   *%ebx

This is the exact same base->method() call. The address of method() is stored into ebx this time. this, however, is loaded from an arbitrary place off the stack!? The program, as expected, crashes. Anyone knows why would the compiler generate assembly like that? I'm still trying to figure it out.

Code

The example code is below. The real code crashes at a point analogous to the example's call to base->check() from invoker->invoke().

Code removed to conserve space. To view it, check the edit history.

Was it helpful?

Solution

It's a bug. (55173, 55367, 55453) The bug is specific to gcc-i686-mingw versions 4.7.0 to 4.7.2.

From 55173:

When a virtual call invoked on an object which uses both virtual and non-virtual inheritance, the virtual thunk leaves the target function with an invalid "this" pointer.

It's basically what I've described in the question. The register that should hold this was used in non-related operations.

The only solution is to downgrade below 4.7.0 or upgrade to 4.7.3 or above.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top