[llvm-bugs] [Bug 36952] New: [MS] Clang fails to emit vftable adjustor thunks when parameter types are incomplete

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Mar 29 15:02:56 PDT 2018


https://bugs.llvm.org/show_bug.cgi?id=36952

            Bug ID: 36952
           Summary: [MS] Clang fails to emit vftable adjustor thunks when
                    parameter types are incomplete
           Product: clang
           Version: unspecified
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: LLVM Codegen
          Assignee: unassignedclangbugs at nondot.org
          Reporter: rnk at google.com
                CC: llvm-bugs at lists.llvm.org

Consider:

$ cat t.h
struct Incomplete;
struct A {
  virtual void foo(Incomplete p) = 0;
};
struct B : virtual A {
  void foo(Incomplete p) override;
};
struct C : B { int c; };

$ cat a.cpp
#include "t.h"
int main() { C c; }

$ cat b.cpp
#include "t.h"
struct Incomplete { void *p; };
void B::foo(Incomplete p) {}

This should produce a valid C++ program, but with clang we get link errors:

$ clang-cl -c a.cpp b.cpp && link -nologo a.obj b.obj -out:t.exe  && ./t.exe
a.obj : error LNK2001: unresolved external symbol "[thunk]:public: virtual void
__cdecl B::foo`adjustor{8}' (struct Incomplete)"
(?foo at B@@W7EAAXUIncomplete@@@Z)
t.exe : fatal error LNK1120: 1 unresolved externals

Reduced from https://crbug.com/822202.

Here are the record layouts:

*** Dumping AST Record Layout
         0 | struct B
         0 |   (B vbtable pointer)
         8 |   struct A (virtual base)
         8 |     (A vftable pointer)
           | [sizeof=16, align=8,
           |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
         0 | struct C
         0 |   struct B (base)
         0 |     (B vbtable pointer)
         8 |   int c
        16 |   struct A (virtual base)
        16 |     (A vftable pointer)
           | [sizeof=24, align=8,
           |  nvsize=16, nvalign=8]

The primary definition of 'B::foo' hardcodes a -8 this adjustment, which
adjusts from A-in-B to the beginning of B.

A is a virtual base, so its location changes relative to B in C's layout. In
C's layout, the offset from A to B is -16, not -8.

C's vftable slot for 'foo' needs to use a thunk to do an additional 8 byte
adjustment so that -8 - 8 = -16, and B::foo's 'this' argument is correctly
positioned. That's where "adjustor{8}" symbol comes from.

So far, Clang implements all that stuff correctly.

The link error comes from the fact we don't have a definition for the
Incomplete struct in a.cpp, so we give up when attempting to emit the thunk
that does the adjustment. We don't emit an error because this code was
originally written to support available_externally vtables for Itanium, so it
was just an optimization, not a correctness issue.

The fix is probably to abuse musttail to emit a thunk without knowing the
prototype for the virtual method.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20180329/2c627292/attachment.html>


More information about the llvm-bugs mailing list