<html>
    <head>
      <base href="http://llvm.org/bugs/" />
    </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 --- - clang++ doesn't export operator delete with -flto"
   href="http://llvm.org/bugs/show_bug.cgi?id=21001">21001</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>clang++ doesn't export operator delete with -flto
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>unspecified
          </td>
        </tr>

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

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

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

        <tr>
          <th>Severity</th>
          <td>normal
          </td>
        </tr>

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

        <tr>
          <th>Component</th>
          <td>C++
          </td>
        </tr>

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

        <tr>
          <th>Reporter</th>
          <td>tavianator@tavianator.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>dgregor@apple.com, llvmbugs@cs.uiuc.edu
          </td>
        </tr>

        <tr>
          <th>Classification</th>
          <td>Unclassified
          </td>
        </tr></table>
      <p>
        <div>
        <pre>When using -flto, clang doesn't export a replacement operator delete, causing
shared libraries to call a different implementation than the main program. 
Example:

$ cat main.cpp
#include <cstdlib>
#include <new>
#include <iostream>

void* operator new(std::size_t size) {
  void* result = std::malloc(size);
  if (result == nullptr) {
    operator delete(result);
    throw std::bad_alloc();
  }
  return result;
}

void operator delete(void* ptr) noexcept {
  std::cout << "Deleting!" << std::endl;
  std::free(ptr);
}

void deleteIt(int* ptr);

int main() {
  deleteIt(new int);
  return 0;
}
$ cat shared.cpp
void deleteIt(int* ptr) {
  delete ptr;
}
$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold -fPIC -shared shared.cpp -o
libshared.so
$ clang++ -std=c++11 -g -O3 -flto -fuse-ld=gold main.cpp -L. -lshared -o main
$ LD_LIBRARY_PATH=. ./main
$

(Note the missing "Deleting!" output.)  objdump shows that the symbol isn't
exported:

$ objdump -T main | c++filt | grep operator
0000000000400e40 g    DF .text  000000000000003a  Base        operator
new(unsigned long)
0000000000000000      DF *UND*  0000000000000000  Base        operator
delete(void*)

The bug happens with C++98 mode too (with appropriate code changes), but the
C++14 operator delete(void*, std::size_t) works.

A workaround is to add __attribute__((used)) to operator delete.  See
<a href="http://stackoverflow.com/q/25922895/502399">http://stackoverflow.com/q/25922895/502399</a>.</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>