<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - -fwhole-program-vtables miscompile when multiple unique return value checks resolve to the same vtable"
   href="https://bugs.llvm.org/show_bug.cgi?id=45393">45393</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>-fwhole-program-vtables miscompile when multiple unique return value checks resolve to the same vtable
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>All
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Interprocedural Optimizations
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>llvm@inglorion.net
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>Created <span class=""><a href="attachment.cgi?id=23305" name="attach_23305" title="Run ninja && ./main">attachment 23305</a> <a href="attachment.cgi?id=23305&action=edit" title="Run ninja && ./main">[details]</a></span>
Run ninja && ./main

class Base {
public:
  virtual bool foo() const { return false; };
  virtual bool bar() const { return false; };
};

class Derived : public Base {
public:
  bool foo() const override { return true; };
  bool bar() const override { return true; };
}

With no other classes in the hierarchy, this allows whole program
devirtualization to replace calls to foo() and bar() with a comparison of the
vptr against Derived's vtable (the methods return true if and only if this is
an instance of Derived).

Because foo() and bar() are in different slots, they are referred to by
different symbols. Code that does something like

  if (foo()) {
    if (bar()) {
      ... }}

translates to something like

  if (vptr == __typeid__ZTSBase_16_unique_member) {
    if (vptr == __typeid__ZTSBase_24_unique_member) {
      ... }}

Because the vtable being checked is the same in both cases, these symbols have
the same value (i.e. they are pointers to the same address).

However, the declarations of these symbols look like

  @__typeid_ZTSBase_16_unique_member = external hidden global i8
  @__typeid_ZTSBase_24_unique_member = external hidden global i8

Because i8 have size, LLVM assumes these globals cannot be at the same address,
concludes the comparison against __typeid__ZTSBase_24_unique_member is always
false, and elides that code.

This was discovered in the analysis of <a href="http://crbug.com/1062006">http://crbug.com/1062006</a>

Some C++ code that reproduces the issue is attached. Running ./main returns 2
when built without -fwhole-program-vtables, and returns 1 when built with
-fwhole-program-vtables, even though that value should be impossible.</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>