[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