From cc5a6c6afeed1d2cf76d288133971d29ee8d893e Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Thu, 13 Aug 2020 11:20:38 +0200 Subject: [PATCH] gcc3_linux_{aarch64,x86-64} need the __cxa_exception hack in deleteException * gcc3_linux_aarch64 needs a hack to detect the reserve member in LLVM >= 10 libcxxabi __cxa_exception, in addition to the existing hack for LLVM 5. On macOS arm64 (which shares the bridges/source/cpp_uno/gcc3_linux_aarch64/ code) we know that we always target a >= LLVM 10 libcxxabi, so we do not need neither of the two hacks there. (And a7d1fed24557b203acb5016a98af26f4ef24d27a "Hack to dynamically adapt to __cxa_exceptiom in LLVM 5.0 libcxxabi" had introduced a "fillUnoException" vs. "mapException" typo in the comment when it copied it from bridges/source/cpp_uno/gcc3_macosx_x86-64/except.cxx.) * Similarly, gcc3_linux_x86_64 needs both hacks when it is built against libcxxabi (and the need for the LLVM 5 hack had gone unnoticed there for now). * It is not clear to me now why gcc3_macosx_x86-64 needs the LLVM 5 hack (which I even initially developed for that platform, 7a9dd3d482deeeb3ed1d50074e56adbd3f928296 "Hack to dynamically adapt to __cxa_exceptiom in LLVM 5.0 libcxxabi") but not the LLVM >= 10 hack (although it does need the corresponding hack in fillUnoException when running against recent upstream LLVM trunk libcxxabi, f4b6f6a8ae60bdec53512728d00853b73fa18500 "Hack to dynamically adapt to __cxa_exceptiom in LLVM 11 libcxxabi". Change-Id: I8e7a5c871fbeeaf82bbd16fa03e73f10f229da93 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100656 Tested-by: Jenkins Reviewed-by: Stephan Bergmann --- .../source/cpp_uno/gcc3_linux_aarch64/abi.cxx | 43 ++++++++++++--- .../cpp_uno/gcc3_linux_x86-64/except.cxx | 53 +++++++++++++++++++ 2 files changed, 88 insertions(+), 8 deletions(-) diff -ru libreoffice-7.0.3.1.orig/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx libreoffice-7.0.3.1/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx --- libreoffice-7.0.3.1.orig/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx 2020-12-11 02:38:41.381272142 -0800 +++ libreoffice-7.0.3.1/bridges/source/cpp_uno/gcc3_linux_aarch64/abi.cxx 2020-12-11 02:40:41.991261582 -0800 @@ -136,8 +136,8 @@ extern "C" void _GLIBCXX_CDTOR_CALLABI deleteException(void * exception) { __cxxabiv1::__cxa_exception * header = static_cast<__cxxabiv1::__cxa_exception *>(exception) - 1; -#if defined _LIBCPPABI_VERSION // detect libc++abi - // The libcxxabi commit +#if !defined MACOSX && defined _LIBCPPABI_VERSION // detect libc++abi + // First, the libcxxabi commit // // "[libcxxabi] Align unwindHeader on a double-word boundary" towards // LLVM 5.0 changed the size of __cxa_exception by adding @@ -147,17 +147,48 @@ // to the final member unwindHeader, on x86-64 effectively adding a hole of // size 8 in front of that member (changing its offset from 88 to 96, // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception) - // from 8 to 16); a hack to dynamically determine whether we run against a - // new libcxxabi is to look at the exceptionDestructor member, which must - // point to this function (the use of __cxa_exception in fillUnoException is + // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a + // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must + // point to this function (the use of __cxa_exception in mapException is // unaffected, as it only accesses members towards the start of the struct, - // through a pointer known to actually point at the start): + // through a pointer known to actually point at the start). The libcxxabi commit + // + // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6 + // removes the need for this hack, so the "header1" hack can be removed again once we can be + // sure that we only run against libcxxabi from LLVM >= 6. + // + // Second, the libcxxabi commit + // + // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed + // the layout of the start of __cxa_exception to + // + // [8 byte void *reserve] + // 8 byte size_t referenceCount + // + // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10 + // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its + // offset by 8. As described in the definition of __cxa_exception + // (bridges/source/cpp_uno/gcc3_linux_aarch64/abi.hxx), the "header2" hack (together with the + // "#ifdef MACOSX" in the definition of __cxa_exception and the corresponding hack in call in + // bridges/source/cpp_uno/gcc3_linux_aarch64/uno2cpp.cxx) can be dropped once we can be sure + // that we only run against new libcxxabi that has the reserve member. if (header->exceptionDestructor != &deleteException) { - header = reinterpret_cast<__cxxabiv1::__cxa_exception *>( + auto const header1 = reinterpret_cast<__cxxabiv1::__cxa_exception *>( reinterpret_cast(header) - 8); - assert(header->exceptionDestructor == &deleteException); + if (header1->exceptionDestructor == &deleteException) { + header = header1; + } else { + auto const header2 = reinterpret_cast<__cxxabiv1::__cxa_exception *>( + reinterpret_cast(header) + 8); + if (header2->exceptionDestructor == &deleteException) { + header = header2; + } else { + assert(false); + } + } } #endif + assert(header->exceptionDestructor == &deleteException); OUString unoName(toUnoName(header->exceptionType->name())); typelib_TypeDescription * td = 0; typelib_typedescription_getByName(&td, unoName.pData); diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx index 981ddfe676f7..2a92dba37475 100644 --- a/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/except.cxx @@ -82,6 +82,59 @@ extern "C" { static void _GLIBCXX_CDTOR_CALLABI deleteException( void * pExc ) { __cxxabiv1::__cxa_exception const * header = static_cast<__cxxabiv1::__cxa_exception const *>(pExc) - 1; +#if defined _LIBCPPABI_VERSION // detect libc++abi + // First, the libcxxabi commit + // + // "[libcxxabi] Align unwindHeader on a double-word boundary" towards + // LLVM 5.0 changed the size of __cxa_exception by adding + // + // __attribute__((aligned)) + // + // to the final member unwindHeader, on x86-64 effectively adding a hole of + // size 8 in front of that member (changing its offset from 88 to 96, + // sizeof(__cxa_exception) from 120 to 128, and alignof(__cxa_exception) + // from 8 to 16); the "header1" hack below to dynamically determine whether we run against a + // LLVM 5 libcxxabi is to look at the exceptionDestructor member, which must + // point to this function (the use of __cxa_exception in fillUnoException is + // unaffected, as it only accesses members towards the start of the struct, + // through a pointer known to actually point at the start). The libcxxabi commit + // + // "Insert padding before the __cxa_exception header to ensure the thrown" in LLVM 6 + // removes the need for this hack, so the "header1" hack can be removed again once we can be + // sure that we only run against libcxxabi from LLVM >= 6. + // + // Second, the libcxxabi commit + // + // "[libcxxabi] Insert padding in __cxa_exception struct for compatibility" in LLVM 10 changed + // the layout of the start of __cxa_exception to + // + // [8 byte void *reserve] + // 8 byte size_t referenceCount + // + // so the "header2" hack below to dynamically determine whether we run against a LLVM >= 10 + // libcxxabi is to look whether the exceptionDestructor (with its known value) has increased its + // offset by 8. As described in the definition of __cxa_exception + // (bridges/source/cpp_uno/gcc3_linux_x86-64/share.hxx), the "header2" hack (together with the + // "#if 0" in the definition of __cxa_exception and the corresponding hack in fillUnoException) + // can be dropped once we can be sure that we only run against new libcxxabi that has the + // reserve member. + if (header->exceptionDestructor != &deleteException) { + auto const header1 = reinterpret_cast<__cxa_exception const *>( + reinterpret_cast(header) - 8); + if (header1->exceptionDestructor == &deleteException) { + header = header1; + } else { + auto const header2 = reinterpret_cast<__cxa_exception const *>( + reinterpret_cast(header) + 8); + if (header2->exceptionDestructor == &deleteException) { + header = header2; + } else { + assert(false); + } + } + } +#endif + assert(header->exceptionDestructor == &deleteException); typelib_TypeDescription * pTD = nullptr; OUString unoName( toUNOname( header->exceptionType->name() ) ); ::typelib_typedescription_getByName( &pTD, unoName.pData );