[Bug libstdc++/96946] libstdc++ std::shared_ptr makes an "unrelated cast" that causes Clang's Control Flow Integrity sanitiser to crash

redi at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Mon Sep 7 12:47:10 GMT 2020


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96946

--- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Ah I see what's wrong. We do the static_cast before creating an object at that
address:

#include <new>

namespace x __attribute__((visibility("default")))
{
template<typename T>
struct buffer
{
  alignas(__alignof__(T)) unsigned char buf[sizeof(T)];

  void* addr() { return static_cast<void*>(buf); }

  T* ptr() { return static_cast<T*>(addr()); }
};
}

struct IReporterFactory {
    virtual ~IReporterFactory() = default;
};

class ReporterFactory : public IReporterFactory {};

int main()
{
  auto p = new x::buffer<ReporterFactory>;
  auto p2 = p->ptr();  // undefined here
  ::new(static_cast<void*>(p2)) ReporterFactory;
  p->ptr()->~ReporterFactory();
  delete p;
}

But we have to do this, because we need to pass a T* to the
allocator_traits::construct function. This clang sanitizer seems incompatible
with any allocator that allocates bytes and then casts std::byte* or unsigned
char* to T*. For example, this also fails at runtime:

#include <memory>

struct IReporterFactory {
    virtual ~IReporterFactory() = default;
};

class ReporterFactory : public IReporterFactory {};

int main()
{
  alignas(alignof(ReporterFactory)) unsigned char b[sizeof(ReporterFactory)];
  using A = std::allocator<ReporterFactory>;
  A a;
  std::allocator_traits<A>::construct(a,
reinterpret_cast<ReporterFactory*>(b));
  std::allocator_traits<A>::destroy(a, reinterpret_cast<ReporterFactory*>(b));
}


More information about the Gcc-bugs mailing list