From 74560f26f75dda4257dce541ca362a1e763b2971 Mon Sep 17 00:00:00 2001
From: Ryan Ofsky <ryan@ofsky.org>
Date: Thu, 6 Feb 2025 08:39:05 -0500
Subject: [PATCH 1/1] Avoid gcc/clang ABI incompatibility caused by
 PlacementNew

GCC and clang do not use same calling convention for passing empty struct
parameters. There is more information about this in
https://itanium-cxx-abi.github.io/cxx-abi/cxx-abi-dev/archives/2015-December/002869.html

Unfortunately this can create an issue in capnproto if it is built without
optimizations in GCC, and the resulting static libraries are used in a clang
program, or vice versa.

Depending on what order libraries are specified on the linker command line, and
whether code compiled with the other compiler is calling any header functions
that cause weak a `operator new(unsigned int, kj::_::PlacementNew, void*)`
symbol to be defined in its own objects, this can cause the linker to link a
GCC-generated `kj::ctor` with a clang-generated `operator new`, and the
resulting program to crash due to the compilers using different calling
conventions for `operator new`.

This problem is difficult to avoid in general, but pretty easy to avoid here by
changing `operator new` parameter order so the empty struct parameter is last.

This change should be beneficial for capnproto users that may be compiling it
without optimizations, and not necessarily using a single compiler to build all
their dependencies.

The problem does not occur if any optimizations are enabled because `operator
new` calls are inlined in that case.
---
 c++/src/kj/common.h | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/c++/src/kj/common.h b/c++/src/kj/common.h
index b8edde3c..28ab11d6 100644
--- a/c++/src/kj/common.h
+++ b/c++/src/kj/common.h
@@ -1034,24 +1034,27 @@ private:
 
 // We want placement new, but we don't want to #include <new>.  operator new cannot be defined in
 // a namespace, and defining it globally conflicts with the definition in <new>.  So we have to
-// define a dummy type and an operator new that uses it.
+// define a dummy type and an operator new that uses it.  The dummy type is intentionally passed
+// as the last parameter so clang and GCC ABI calling conventions for empty struct struct parameters
+// are compatible, and there are not segfaults trying to call clang operator new/delete from GCC or
+// vice versa.
 
 namespace _ {  // private
 struct PlacementNew {};
 }  // namespace _ (private)
 } // namespace kj
 
-inline void* operator new(size_t, kj::_::PlacementNew, void* __p) noexcept {
+inline void* operator new(size_t, void* __p, kj::_::PlacementNew) noexcept {
   return __p;
 }
 
-inline void operator delete(void*, kj::_::PlacementNew, void* __p) noexcept {}
+inline void operator delete(void*, void* __p, kj::_::PlacementNew) noexcept {}
 
 namespace kj {
 
 template <typename T, typename... Params>
 inline void ctor(T& location, Params&&... params) {
-  new (_::PlacementNew(), &location) T(kj::fwd<Params>(params)...);
+  new (&location, _::PlacementNew()) T(kj::fwd<Params>(params)...);
 }
 
 template <typename T>
