This is an automated email from the ASF dual-hosted git repository.
jimjag pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git
The following commit(s) were added to refs/heads/trunk by this push:
new 4ca7e75a8a bridges: add arm64 RTTI synthesis QA harnesses
4ca7e75a8a is described below
commit 4ca7e75a8a392f3dadfa2bcceac9342116803c9d
Author: Jim Jagielski <[email protected]>
AuthorDate: Mon Aug 3 14:36:56 2026 -0400
bridges: add arm64 RTTI synthesis QA harnesses
---
.../qa/keyless_rtti_visibility_demo.cxx | 19 ++++
.../qa/rtti_crossdylib_test/catcher.cxx | 10 ++
.../qa/rtti_crossdylib_test/thrower.cxx | 47 ++++++++
.../qa/rtti_crossdylib_test/uno_like.hxx | 5 +
.../qa/rtti_synthesis_test.cxx | 120 +++++++++++++++++++++
5 files changed, 201 insertions(+)
diff --git
a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/keyless_rtti_visibility_demo.cxx
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/keyless_rtti_visibility_demo.cxx
new file mode 100644
index 0000000000..b066071014
--- /dev/null
+++
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/keyless_rtti_visibility_demo.cxx
@@ -0,0 +1,19 @@
+// Demonstrates why arm64 Darwin needs the RTTI synthesis in except.cxx: a
+// class with no key function (every UNO exception, since they declare no
+// virtual functions) gets hidden ("weak private external") typeinfo on
+// arm64 regardless of visibility attributes, whereas the same class gets
+// exported ("weak external") typeinfo on x86_64. Compare:
+//
+// clang++ -arch arm64 -c keyless_rtti_visibility_demo.cxx && nm -m
keyless_rtti_visibility_demo.o | grep __ZTI
+// clang++ -arch x86_64 -c keyless_rtti_visibility_demo.cxx && nm -m
keyless_rtti_visibility_demo.o | grep __ZTI
+//
+// A/B (keyless) are hidden on arm64 and exported on x86_64; C/D (have a key
+// function) are exported on both, with or without the visibility attribute.
+struct A { int x; };
+struct __attribute__((visibility("default"))) B { int x; };
+struct C { int x; virtual void key(); };
+void C::key() {}
+struct __attribute__((visibility("default"))) D { int x; virtual void key(); };
+void D::key() {}
+#include <typeinfo>
+const void* refs[] = { &typeid(A), &typeid(B), &typeid(C), &typeid(D) };
diff --git
a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/catcher.cxx
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/catcher.cxx
new file mode 100644
index 0000000000..8fdbcb5324
--- /dev/null
+++
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/catcher.cxx
@@ -0,0 +1,10 @@
+// See thrower.cxx for build/run instructions and expected output.
+#include "uno_like.hxx"
+#include <cstdio>
+extern "C" void throw_synth();
+int main() {
+ try { throw_synth(); }
+ catch (com::sun::star::ucb::InteractiveAugmentedIOException&) {
printf("RESULT: caught as EXACT derived type (WORKS)\n"); return 0; }
+ catch (com::sun::star::uno::Exception&) { printf("RESULT: caught as BASE
css::uno::Exception (WORKS)\n"); return 0; }
+ catch (...) { printf("RESULT: caught only by catch(...) (BROKEN)\n");
return 1; }
+}
diff --git
a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/thrower.cxx
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/thrower.cxx
new file mode 100644
index 0000000000..acc100be5d
--- /dev/null
+++
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/thrower.cxx
@@ -0,0 +1,47 @@
+// Cross-image ABI harness: synthesizes RTTI for a whole exception chain
+// (neither type dlsym-able, mirroring how the real bridge is used) and
+// throws it from a separate dylib. Not wired into gbuild; build and run
+// manually:
+//
+// clang++ -std=c++11 -arch arm64 -dynamiclib -o libthrower.dylib
thrower.cxx \
+// -install_name @rpath/libthrower.dylib
+// clang++ -std=c++11 -arch arm64 -o catcher catcher.cxx -L. -lthrower \
+// -Wl,-rpath,@executable_path
+// ./catcher
+//
+// Expected: "RESULT: caught as EXACT derived type (WORKS)".
+#include "uno_like.hxx"
+#include <typeinfo>
+#include <cstring>
+#include <cstdlib>
+#include <cstdint>
+#include <cstdio>
+extern "C" void* __cxa_allocate_exception(size_t) throw();
+extern "C" void __cxa_throw(void*, std::type_info*, void (*)(void*))
__attribute__((noreturn));
+// vtable donors: real, compiler-emitted, in THIS dylib
+namespace { struct DonorBase { int a; }; struct DonorDerived : DonorBase { int
b; }; }
+struct ClassTi { void const* vptr; uintptr_t name; };
+struct SiTi { void const* vptr; uintptr_t name; void const* base; };
+static const uintptr_t NONUNIQUE = 1ULL << 63;
+static uintptr_t mkname(const char* s){ return (uintptr_t)strdup(s) |
NONUNIQUE; }
+static std::type_info* synth_base() {
+ static ClassTi* t = 0;
+ if (!t) { t = (ClassTi*)calloc(1,sizeof(ClassTi));
+ t->vptr = ((ClassTi const*)&typeid(DonorBase))->vptr;
+ t->name = mkname("N3com3sun4star3uno9ExceptionE"); }
+ return (std::type_info*)t;
+}
+static std::type_info* synth_derived() {
+ static SiTi* t = 0;
+ if (!t) { t = (SiTi*)calloc(1,sizeof(SiTi));
+ t->vptr = ((SiTi const*)&typeid(DonorDerived))->vptr;
+ t->name =
mkname("N3com3sun4star3ucb31InteractiveAugmentedIOExceptionE");
+ t->base = synth_base(); }
+ return (std::type_info*)t;
+}
+static void nodel(void*) {}
+extern "C" __attribute__((visibility("default"))) void throw_synth() {
+ void* e =
__cxa_allocate_exception(sizeof(com::sun::star::ucb::InteractiveAugmentedIOException));
+ memset(e,0,sizeof(com::sun::star::ucb::InteractiveAugmentedIOException));
+ __cxa_throw(e, synth_derived(), nodel);
+}
diff --git
a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/uno_like.hxx
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/uno_like.hxx
new file mode 100644
index 0000000000..5f1ed6b9c3
--- /dev/null
+++
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_crossdylib_test/uno_like.hxx
@@ -0,0 +1,5 @@
+#pragma once
+namespace com { namespace sun { namespace star {
+namespace uno { struct Exception { char* Message; void* Context; }; }
+namespace ucb { struct InteractiveAugmentedIOException : public
::com::sun::star::uno::Exception { int code; }; }
+}}}
diff --git
a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_synthesis_test.cxx
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_synthesis_test.cxx
new file mode 100644
index 0000000000..272a0d7eef
--- /dev/null
+++
b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/qa/rtti_synthesis_test.cxx
@@ -0,0 +1,120 @@
+// Standalone ABI harness for the RTTI synthesis in ../except.cxx and
+// ../share.hxx. Not wired into gbuild; compile and run manually:
+//
+// clang++ -std=c++11 -arch arm64 -o rtti_synthesis_test
rtti_synthesis_test.cxx
+// ./rtti_synthesis_test
+//
+// Expected output: test 3 and both variants of test 2 report CAUGHT; only
+// test 1 (the naive hand-built type_info, i.e. the approach the
+// s5abi_macosx_x86-64 bridge uses) reports the catch(...) fallback.
+//
+// Does libc++abi on arm64 Darwin catch an exception thrown with a hand-built
+// type_info? Mirrors what bridges/.../s5abi_macosx_x86-64/except.cxx does.
+#include <cxxabi.h>
+#include <typeinfo>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <cstdint>
+
+// ---- UNO-like plain structs (no virtual functions), as css::uno::Exception
is
+struct UnoException { char* Message; void* Context; };
+struct UnoRealDerived : UnoException { int extra; }; // typeid -> real
__si_class_type_info
+
+// ---- AOO's stand-ins, copied verbatim in shape from s5abi share.hxx ----
+namespace fake {
+class __class_type_info : public std::type_info {
+public:
+ explicit __class_type_info(const char* n) : std::type_info(n) {}
+};
+class __si_class_type_info : public __class_type_info {
+ const __class_type_info* mpBaseType;
+public:
+ __si_class_type_info(const char* n, __class_type_info* b)
+ : __class_type_info(n), mpBaseType(b) {}
+};
+}
+
+// Itanium layout of __cxxabiv1::__si_class_type_info
+struct SiLayout {
+ void const* vptr;
+ char const* name;
+ void const* base;
+};
+
+extern "C" void* __cxa_allocate_exception(size_t) throw();
+extern "C" void __cxa_throw(void*, std::type_info*, void (*)(void*))
__attribute__((noreturn));
+
+static void nodelete(void*) {}
+
+static void report(const char* what, int r) {
+ printf("%-46s : %s\n", what,
+ r == 1 ? "CAUGHT as UnoException& (WORKS)"
+ : r == 2 ? "caught only by catch(...) (BROKEN)"
+ : "??");
+}
+
+// Test 1: naive hand-built type_info (foreign vtable) -- what AOO x86-64 does
+static int test_naive() {
+ static fake::__si_class_type_info* ti =
+ new fake::__si_class_type_info(
+ strdup("N3com3sun4star3ucb31InteractiveAugmentedIOExceptionE"),
+
(fake::__class_type_info*)const_cast<std::type_info*>(&typeid(UnoException)));
+ void* e = __cxa_allocate_exception(sizeof(UnoException));
+ memset(e, 0, sizeof(UnoException));
+ try {
+ __cxa_throw(e, (std::type_info*)ti, nodelete);
+ } catch (UnoException&) { return 1; }
+ catch (...) { return 2; }
+ return 0;
+}
+
+// Test 2: vtable borrowed from a real compiler-emitted __si_class_type_info
+static int test_vtable_borrow(bool set_nonunique_bit) {
+ SiLayout const* model =
+ reinterpret_cast<SiLayout const*>(&typeid(UnoRealDerived));
+ SiLayout* ti = (SiLayout*)calloc(1, sizeof(SiLayout));
+ ti->vptr = model->vptr;
+ char const* nm =
strdup("N3com3sun4star3ucb31InteractiveAugmentedIOExceptionE");
+ if (set_nonunique_bit)
+ nm = (char const*)((uintptr_t)nm | (1ULL << 63));
+ ti->name = nm;
+ ti->base = &typeid(UnoException);
+ void* e = __cxa_allocate_exception(sizeof(UnoException));
+ memset(e, 0, sizeof(UnoException));
+ try {
+ __cxa_throw(e, (std::type_info*)ti, nodelete);
+ } catch (UnoException&) { return 1; }
+ catch (...) { return 2; }
+ return 0;
+}
+
+// Test 3: sanity -- a genuinely compiler-emitted derived type
+static int test_real() {
+ void* e = __cxa_allocate_exception(sizeof(UnoRealDerived));
+ memset(e, 0, sizeof(UnoRealDerived));
+ try {
+ __cxa_throw(e, (std::type_info*)&typeid(UnoRealDerived), nodelete);
+ } catch (UnoException&) { return 1; }
+ catch (...) { return 2; }
+ return 0;
+}
+
+int main() {
+ printf("_LIBCPP_TYPEINFO_COMPARISON_IMPLEMENTATION-relevant arch: %s\n",
+#if defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__)
+ "arm64 Apple -> NonUniqueARMRTTIBit (impl 3)");
+#else
+ "other");
+#endif
+ SiLayout const* m = reinterpret_cast<SiLayout
const*>(&typeid(UnoRealDerived));
+ printf("real typeid(UnoRealDerived).name ptr = %p high bit=%d str=%s\n",
+ (void*)m->name, (int)(((uintptr_t)m->name) >> 63),
+ typeid(UnoRealDerived).name());
+ printf("\n");
+ report("3: real compiler-emitted typeinfo (control)", test_real());
+ report("1: naive hand-built (AOO x86-64 approach)", test_naive());
+ report("2a: borrowed vtable, plain name",
test_vtable_borrow(false));
+ report("2b: borrowed vtable, non-unique bit set",
test_vtable_borrow(true));
+ return 0;
+}