From ef533553559fe09b4afab651fc692885d1acf4ed Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Wed, 4 Jan 2023 12:14:22 +0100 Subject: Rudimentary support for dynamic_cast on UNO proxy objects "New loplugin:unocast" had argued that uses of dynamic_cast from a UNO interface type are broken in general (because if the source object is a proxy from the C*+ UNO bridge, its vtable's RTTI slot will normally not be set up, which can cause a crash), and should be replaced with uses of XUnoTunnel. Which the various recent "loplugin:unocast (...)" commits started to do. However, it became clear that that is not the most ideal way forward: For one, getting more and more implementations of XUnoTunnel::getSomething into existing class hierarchies is error prone, as each such implementation must manually delegate to all its base class implementations. For another, uses of comphelper::getFromUnoTunnel (which often needs to do a queryInterface to XUnoTunnel first) are easily more expensive than uses of dynamic_cast. Thanks to Noel, the insight here is that for the use case of a dynamic_cast from a UNO interface type to a local C++ class type, and if the source object is a proxy, it is sufficient that the dynamic_cast will not crash. It will necessarily always return null (as the proxy will never be the implementation of a local C++ class type), so it is sufficient to fill the RTTI slots of the proxies' vtables with dummy values. That avoids having to set up proper RTTI for those potentially multiple-inheritance proxy types. (And with this in place, all those recent "loplugin:unocast (...)" commits can be reverted again in a next step.) I verified the changes for the gcc3_linux_aarch64 (on macOS), gcc3_linux_intel, gcc3_linux_x86-64, gcc3_macosx_x86-64, msvc_win32_intel, and msvc_win32_x86-64 bridges. The changes for all the other bridges were done blindly. (For gcc3_linux_x86-64, which already conditionally supported proper RTTI for UBSan, setting the offset-to-top slot to non-zero had to be made conditional too, as the dummy ProxyRtti will always pretend to be a full class rather than a potential base class that could have a non-zero offset-to-top value. For msvc_win32_*, it turned out that the existing code to set up dummy XInterface RTTI (which was there for reasons lost to history) was broken.) Change-Id: Iec4b8067d26b14b6fb02c2fdd15e1eee20919590 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145038 Tested-by: Jenkins Reviewed-by: Stephan Bergmann --- .../source/cpp_uno/gcc3_aix_powerpc/cpp2uno.cxx | 11 +- bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx | 15 ++- .../source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx | 11 +- bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx | 11 +- bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx | 11 +- bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx | 9 +- .../source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx | 14 ++- .../cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx | 14 ++- bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx | 11 +- bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx | 11 +- .../cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx | 14 ++- bridges/source/cpp_uno/gcc3_linux_s390/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx | 14 ++- .../source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx | 14 ++- .../source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx | 17 +++- .../source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_solaris_intel/cpp2uno.cxx | 11 +- .../source/cpp_uno/gcc3_solaris_sparc/cpp2uno.cxx | 14 ++- .../source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx | 113 ++++++++++++++++++--- .../source/cpp_uno/msvc_win32_intel/cpp2uno.cxx | 79 ++++++++++++-- .../source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx | 89 ++++++++++++++-- testtools/source/bridgetest/bridgetest.cxx | 4 + 27 files changed, 487 insertions(+), 77 deletions(-) diff --git a/bridges/source/cpp_uno/gcc3_aix_powerpc/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_aix_powerpc/cpp2uno.cxx index 2e6fdd11a820..92068152245c 100644 --- a/bridges/source/cpp_uno/gcc3_aix_powerpc/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_aix_powerpc/cpp2uno.cxx @@ -30,6 +30,7 @@ #include "share.hxx" #include +#include using namespace ::com::sun::star::uno; @@ -571,7 +572,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bp __asm__ volatile ("isync" : : : "memory"); } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -585,6 +586,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -592,7 +599,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx index 21de11b5ea36..9ba5af012443 100644 --- a/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_ios/cpp2uno.cxx @@ -16,6 +16,11 @@ * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ + +#include + +#include + #include #include #include @@ -457,7 +462,7 @@ namespace } } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -471,6 +476,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot); } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -478,7 +489,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx index 775a4aff6962..669c4443c5f0 100644 --- a/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_aarch64/cpp2uno.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -502,7 +503,7 @@ unsigned char * generateCodeSnippet( } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) { @@ -515,6 +516,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -522,7 +529,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = nullptr; - slots[-1].fn = nullptr; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx index bd0be3981d7c..98709f4c5e90 100644 --- a/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_alpha/cpp2uno.cxx @@ -30,6 +30,7 @@ #include "share.hxx" #include +#include //Calling Standards: // "Calling Standard for Alpha Systems" @@ -585,7 +586,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, u __asm__ __volatile__("call_pal 0x86"); } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -599,6 +600,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -606,7 +613,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx index 103f2b492e3a..f476cf7df10b 100644 --- a/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_arm/cpp2uno.cxx @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -484,7 +485,7 @@ namespace } } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -498,6 +499,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -505,7 +512,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = nullptr; - slots[-1].fn = nullptr; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx index 5491e0153b7e..7e8524d1c726 100644 --- a/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_hppa/cpp2uno.cxx @@ -18,6 +18,7 @@ */ #include +#include #include @@ -629,7 +630,7 @@ namespace } } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -643,6 +644,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -650,7 +657,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx index ddcd40818036..0d8303861c28 100644 --- a/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_ia64/cpp2uno.cxx @@ -30,6 +30,7 @@ #include "share.hxx" #include +#include extern "C" { extern void (*privateSnippetExecutor)(); } @@ -607,10 +608,16 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot* bridges::cpp_uno::shared::VtableFactory::initializeBlock(void * block, sal_Int32 slotCount, sal_Int32, typelib_InterfaceTypeDescription *) { Slot * slots = mapBlockToVtable(block); - slots[-1] = {0,0}; + slots[-1] = {0,reinterpret_cast(&typeid(ProxyRtti))}; return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx index 70c6091ec207..5dd6e1aa90f1 100644 --- a/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_intel/cpp2uno.cxx @@ -18,6 +18,10 @@ */ +#include + +#include + #include #include #include @@ -438,7 +442,7 @@ unsigned char * codeSnippet( } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) { @@ -451,6 +455,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -458,7 +468,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = nullptr; - slots[-1].fn = nullptr; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx index 0273b39da4e3..d0c1ce900501 100644 --- a/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_loongarch64/cpp2uno.cxx @@ -31,6 +31,7 @@ #include #include +#include using namespace com::sun::star::uno; @@ -480,7 +481,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const* bpt struct bridges::cpp_uno::shared::VtableFactory::Slot { - void* fn; + void const* fn; }; bridges::cpp_uno::shared::VtableFactory::Slot* @@ -494,6 +495,15 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slot return (slotCount + 2) * sizeof(Slot) + slotCount * codeSnippetSize; } +namespace +{ +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti +{ +}; +} + bridges::cpp_uno::shared::VtableFactory::Slot* bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount, sal_Int32, @@ -501,7 +511,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 { Slot* slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx index c293f3ce6b64..ac375e052bf6 100644 --- a/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_m68k/cpp2uno.cxx @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -441,7 +442,7 @@ namespace } } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -455,6 +456,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -462,7 +469,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx index 35e1f231d770..21ec313942ac 100644 --- a/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_mips/cpp2uno.cxx @@ -29,6 +29,7 @@ #include #include +#include using namespace com::sun::star::uno; @@ -719,7 +720,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *bpt #endif } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -734,6 +735,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -741,7 +748,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx index ebde9821eab2..7dbf0022e963 100644 --- a/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_mips64/cpp2uno.cxx @@ -30,6 +30,7 @@ #include #include +#include using namespace com::sun::star::uno; @@ -616,7 +617,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *bpt #endif } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -631,6 +632,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -638,7 +645,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx index 521dccd6dae1..328fb7a17e38 100644 --- a/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_powerpc/cpp2uno.cxx @@ -19,6 +19,7 @@ #include +#include #include #include @@ -702,7 +703,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bp __asm__ volatile ("isync" : : : "memory"); } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -716,6 +717,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -723,7 +730,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx index ab3fbd4c76b3..d1a5ee6f4e76 100644 --- a/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_powerpc64/cpp2uno.cxx @@ -31,6 +31,7 @@ #include "share.hxx" #include #include +#include #ifdef OSL_BIGENDIAN #define IS_BIG_ENDIAN 1 @@ -664,7 +665,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const * bp __asm__ volatile ("isync" : : : "memory"); } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -678,6 +679,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -685,7 +692,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx index 6af52e9e471a..16f6ba27c0f4 100644 --- a/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_riscv64/cpp2uno.cxx @@ -32,6 +32,7 @@ #include //#include #include +#include using namespace com::sun::star::uno; @@ -709,7 +710,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const* bpt struct bridges::cpp_uno::shared::VtableFactory::Slot { - void* fn; + void const* fn; }; bridges::cpp_uno::shared::VtableFactory::Slot* @@ -723,6 +724,15 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slot return (slotCount + 2) * sizeof(Slot) + slotCount * codeSnippetSize; } +namespace +{ +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti +{ +}; +} + bridges::cpp_uno::shared::VtableFactory::Slot* bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount, sal_Int32, @@ -730,7 +740,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 { Slot* slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_s390/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_s390/cpp2uno.cxx index b9e61b148304..aca33d1ae511 100644 --- a/bridges/source/cpp_uno/gcc3_linux_s390/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_s390/cpp2uno.cxx @@ -31,6 +31,7 @@ #include "share.hxx" #include #include +#include using namespace ::com::sun::star::uno; @@ -602,7 +603,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, u { } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -616,6 +617,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -623,7 +630,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx index ed48be648bca..285d1241a2d5 100644 --- a/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_s390x/cpp2uno.cxx @@ -30,6 +30,7 @@ #include "share.hxx" #include +#include using namespace ::com::sun::star::uno; @@ -565,7 +566,7 @@ void bridges::cpp_uno::shared::VtableFactory::flushCode(unsigned char const *, u { } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -579,6 +580,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -586,7 +593,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx index 8afbd04a7161..950d644df106 100644 --- a/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_sparc/cpp2uno.cxx @@ -17,6 +17,10 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include + +#include + #include #include #include @@ -477,7 +481,7 @@ unsigned char * codeSnippet( } //end of namespace -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -491,6 +495,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -498,7 +508,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx index 9b157f082120..f455be45dc88 100644 --- a/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_sparc64/cpp2uno.cxx @@ -17,6 +17,10 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include + +#include + #include #include #include @@ -650,7 +654,7 @@ unsigned char * codeSnippet( } //end of namespace -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -664,6 +668,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -671,7 +681,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx index f400c766a2e6..7466d0e225bc 100644 --- a/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_linux_x86-64/cpp2uno.cxx @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -445,7 +446,7 @@ static unsigned char * codeSnippet( unsigned char * code, return code + codeSnippetSize; } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -459,17 +460,27 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +#if ENABLE_RUNTIME_OPTIMIZATIONS +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} +#endif + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription * type) { Slot * slots = mapBlockToVtable(block); - slots[-2].fn = reinterpret_cast(-(vtableNumber * sizeof (void *))); #if ENABLE_RUNTIME_OPTIMIZATIONS - slots[-1].fn = nullptr; + slots[-2].fn = nullptr; + slots[-1].fn = &typeid(ProxyRtti); + (void)vtableNumber; (void)type; #else + slots[-2].fn = reinterpret_cast(-(vtableNumber * sizeof (void *))); slots[-1].fn = x86_64::getRtti(type->aBase); #endif return slots + slotCount; diff --git a/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx index efdf211d8a6e..11426e9475b2 100644 --- a/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_macosx_x86-64/cpp2uno.cxx @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -453,7 +454,7 @@ static unsigned char * codeSnippet( unsigned char * code, return code + codeSnippetSize; } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -467,6 +468,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -474,7 +481,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = nullptr; - slots[-1].fn = nullptr; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_solaris_intel/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_solaris_intel/cpp2uno.cxx index 5609bd6dc839..33687f1d0a02 100644 --- a/bridges/source/cpp_uno/gcc3_solaris_intel/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_solaris_intel/cpp2uno.cxx @@ -20,6 +20,7 @@ #include #include +#include #include #include "com/sun/star/uno/RuntimeException.hpp" @@ -431,7 +432,7 @@ unsigned char * codeSnippet( } -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -445,6 +446,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -452,7 +459,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; - slots[-1].fn = 0; + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/gcc3_solaris_sparc/cpp2uno.cxx b/bridges/source/cpp_uno/gcc3_solaris_sparc/cpp2uno.cxx index 639b8da3dc88..55c1360f844e 100644 --- a/bridges/source/cpp_uno/gcc3_solaris_sparc/cpp2uno.cxx +++ b/bridges/source/cpp_uno/gcc3_solaris_sparc/cpp2uno.cxx @@ -17,6 +17,10 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ +#include + +#include + #include #include #include @@ -475,7 +479,7 @@ unsigned char * codeSnippet( } //end of namespace -struct bridges::cpp_uno::shared::VtableFactory::Slot { void * fn; }; +struct bridges::cpp_uno::shared::VtableFactory::Slot { void const * fn; }; bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::mapBlockToVtable(void * block) @@ -489,6 +493,12 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 2) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, @@ -496,7 +506,7 @@ bridges::cpp_uno::shared::VtableFactory::initializeBlock( { Slot * slots = mapBlockToVtable(block); slots[-2].fn = 0; //null - slots[-1].fn = 0; //destructor + slots[-1].fn = &typeid(ProxyRtti); return slots + slotCount; } diff --git a/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx index cfefa60e748a..fc956121dc07 100644 --- a/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/msvc_win32_arm64/cpp2uno.cxx @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -42,6 +44,8 @@ #include "abi.hxx" +extern "C" IMAGE_DOS_HEADER const __ImageBase; + extern "C" void vtableSlotCall(); using namespace ::com::sun::star; @@ -357,27 +361,110 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize(sal_Int32 slot return (slotCount + 1) * sizeof(Slot) + slotCount * codeSnippetSize; } +static sal_uInt32 imageRelative(void const* p) +{ + assert(reinterpret_cast(p) >= reinterpret_cast(&__ImageBase) + && reinterpret_cast(p) - reinterpret_cast(&__ImageBase) + <= std::numeric_limits::max()); + return reinterpret_cast(p) - reinterpret_cast(&__ImageBase); +} + +namespace +{ +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti +{ +}; + +// The following vtable RTTI data is based on how the code at +// computes +// such data, and on how +// "Accessing the current module’s HINSTANCE from a static library" obtians __ImageBase: + +struct RttiClassHierarchyDescriptor; + +#pragma warning(push) +#pragma warning(disable : 4324) // "structure was padded due to alignment specifier" + +struct alignas(16) RttiBaseClassDescriptor +{ + sal_uInt32 n0 = imageRelative(&typeid(ProxyRtti)); + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 0; + sal_uInt32 n3 = 0xFFFFFFFF; + sal_uInt32 n4 = 0; + sal_uInt32 n5 = 0x40; + sal_uInt32 n6; + RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const* chd) + : n6(imageRelative(chd)) + { + } +}; + +struct alignas(4) RttiBaseClassArray +{ + sal_uInt32 n0; + sal_uInt32 n1 = 0; + RttiBaseClassArray(RttiBaseClassDescriptor const* bcd) + : n0(imageRelative(bcd)) + { + } +}; + +struct alignas(8) RttiClassHierarchyDescriptor +{ + sal_uInt32 n0 = 0; + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 1; + sal_uInt32 n3; + RttiClassHierarchyDescriptor(RttiBaseClassArray const* bca) + : n3(imageRelative(bca)) + { + } +}; + +struct alignas(16) RttiCompleteObjectLocator +{ + sal_uInt32 n0 = 1; + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 0; + sal_uInt32 n3 = imageRelative(&typeid(ProxyRtti)); + sal_uInt32 n4; + sal_uInt32 n5 = imageRelative(this); + RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const* chd) + : n4(imageRelative(chd)) + { + } +}; + +struct Rtti +{ + RttiBaseClassDescriptor bcd; + RttiBaseClassArray bca; + RttiClassHierarchyDescriptor chd; + RttiCompleteObjectLocator col; + Rtti() + : bcd(&chd) + , bca(&bcd) + , chd(&bca) + , col(&chd) + { + } +}; + +#pragma warning(pop) +} + bridges::cpp_uno::shared::VtableFactory::Slot* bridges::cpp_uno::shared::VtableFactory::initializeBlock(void* block, sal_Int32 slotCount, sal_Int32, typelib_InterfaceTypeDescription*) { - struct Rtti - { - sal_Int32 n0, n1, n2; - type_info* rtti; - Rtti() - : n0(0) - , n1(0) - , n2(0) - , rtti(RTTInfos::get("com.sun.star.uno.XInterface")) - { - } - }; static Rtti rtti; Slot* slots = mapBlockToVtable(block); - slots[-1].fn = &rtti; + slots[-1].fn = &rtti.col; return slots + slotCount; } diff --git a/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx index 0908c7666b50..577c318c5767 100644 --- a/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx +++ b/bridges/source/cpp_uno/msvc_win32_intel/cpp2uno.cxx @@ -18,6 +18,10 @@ */ +#include + +#include + #include #include @@ -124,23 +128,80 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize; } +namespace { + +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; + +// The following vtable RTTI data is based on how the code at +// computes +// such data: + +struct RttiClassHierarchyDescriptor; + +#pragma warning (push) +#pragma warning (disable: 4324) // "structure was padded due to alignment specifier" + +struct alignas(16) RttiBaseClassDescriptor { + sal_uInt32 n0 = reinterpret_cast(&typeid(ProxyRtti)); + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 0; + sal_uInt32 n3 = 0xFFFFFFFF; + sal_uInt32 n4 = 0; + sal_uInt32 n5 = 0x40; + sal_uInt32 n6; + RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const * chd): + n6(reinterpret_cast(chd)) {} +}; + +struct alignas(4) RttiBaseClassArray { + sal_uInt32 n0; + sal_uInt32 n1 = 0; + RttiBaseClassArray(RttiBaseClassDescriptor const * bcd): n0(reinterpret_cast(bcd)) + {} +}; + +struct alignas(4) RttiClassHierarchyDescriptor { + sal_uInt32 n0 = 0; + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 1; + sal_uInt32 n3; + RttiClassHierarchyDescriptor(RttiBaseClassArray const * bca): + n3(reinterpret_cast(bca)) {} +}; + +struct alignas(16) RttiCompleteObjectLocator { + sal_uInt32 n0 = 0; + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 0; + sal_uInt32 n3 = reinterpret_cast(&typeid(ProxyRtti)); + sal_uInt32 n4; + RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const * chd): + n4(reinterpret_cast(chd)) {} +}; + +struct Rtti { + RttiBaseClassDescriptor bcd; + RttiBaseClassArray bca; + RttiClassHierarchyDescriptor chd; + RttiCompleteObjectLocator col; + Rtti(): bcd(&chd), bca(&bcd), chd(&bca), col(&chd) {} +}; + +#pragma warning (pop) + +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, typelib_InterfaceTypeDescription *) { - struct Rtti { - sal_Int32 n0, n1, n2; - type_info * rtti; - Rtti(): - n0(0), n1(0), n2(0), - rtti(RTTInfos::get("com.sun.star.uno.XInterface")) - {} - }; static Rtti rtti; Slot * slots = mapBlockToVtable(block); - slots[-1].fn = &rtti; + slots[-1].fn = &rtti.col; return slots + slotCount; } diff --git a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx index 159eb99a4756..974a4a94d48b 100644 --- a/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx +++ b/bridges/source/cpp_uno/msvc_win32_x86-64/cpp2uno.cxx @@ -18,6 +18,12 @@ */ +#include + +#include +#include +#include + #include #include @@ -34,6 +40,8 @@ #include #include +extern "C" IMAGE_DOS_HEADER const __ImageBase; + using namespace ::com::sun::star; extern "C" typelib_TypeClass cpp_vtable_call(sal_Int64 nOffsetAndIndex, void ** pCallStack) @@ -141,24 +149,87 @@ std::size_t bridges::cpp_uno::shared::VtableFactory::getBlockSize( return (slotCount + 1) * sizeof (Slot) + slotCount * codeSnippetSize; } +static sal_uInt32 imageRelative(void const * p) { + assert( + reinterpret_cast(p) >= reinterpret_cast(&__ImageBase) + && reinterpret_cast(p) - reinterpret_cast(&__ImageBase) + <= std::numeric_limits::max()); + return reinterpret_cast(p) - reinterpret_cast(&__ImageBase); +} + +namespace { + +// Some dummy type whose RTTI is used in the synthesized proxy vtables to make uses of dynamic_cast +// on such proxy objects not crash: +struct ProxyRtti {}; + +// The following vtable RTTI data is based on how the code at +// computes +// such data, and on how +// "Accessing the current module’s HINSTANCE from a static library" obtians __ImageBase: + +struct RttiClassHierarchyDescriptor; + +#pragma warning (push) +#pragma warning (disable: 4324) // "structure was padded due to alignment specifier" + +struct alignas(16) RttiBaseClassDescriptor { + sal_uInt32 n0 = imageRelative(&typeid(ProxyRtti)); + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 0; + sal_uInt32 n3 = 0xFFFFFFFF; + sal_uInt32 n4 = 0; + sal_uInt32 n5 = 0x40; + sal_uInt32 n6; + RttiBaseClassDescriptor(RttiClassHierarchyDescriptor const * chd): n6(imageRelative(chd)) {} +}; + +struct alignas(4) RttiBaseClassArray { + sal_uInt32 n0; + sal_uInt32 n1 = 0; + RttiBaseClassArray(RttiBaseClassDescriptor const * bcd): n0(imageRelative(bcd)) {} +}; + +struct alignas(8) RttiClassHierarchyDescriptor { + sal_uInt32 n0 = 0; + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 1; + sal_uInt32 n3; + RttiClassHierarchyDescriptor(RttiBaseClassArray const * bca): n3(imageRelative(bca)) {} +}; + +struct alignas(16) RttiCompleteObjectLocator { + sal_uInt32 n0 = 1; + sal_uInt32 n1 = 0; + sal_uInt32 n2 = 0; + sal_uInt32 n3 = imageRelative(&typeid(ProxyRtti)); + sal_uInt32 n4; + sal_uInt32 n5 = imageRelative(this); + RttiCompleteObjectLocator(RttiClassHierarchyDescriptor const * chd): n4(imageRelative(chd)) {} +}; + +struct Rtti { + RttiBaseClassDescriptor bcd; + RttiBaseClassArray bca; + RttiClassHierarchyDescriptor chd; + RttiCompleteObjectLocator col; + Rtti(): bcd(&chd), bca(&bcd), chd(&bca), col(&chd) {} +}; + +#pragma warning (pop) + +} + bridges::cpp_uno::shared::VtableFactory::Slot * bridges::cpp_uno::shared::VtableFactory::initializeBlock( void * block, sal_Int32 slotCount, sal_Int32, typelib_InterfaceTypeDescription *) { - struct Rtti { - sal_Int32 n0, n1, n2; - type_info * rtti; - Rtti(): - n0(0), n1(0), n2(0), - rtti(RTTInfos::get("com.sun.star.uno.XInterface")) - {} - }; static Rtti rtti; Slot * slots = mapBlockToVtable(block); - slots[-1].fn = &rtti; + slots[-1].fn = &rtti.col; return slots + slotCount; } diff --git a/testtools/source/bridgetest/bridgetest.cxx b/testtools/source/bridgetest/bridgetest.cxx index 78bcdc6f0d3a..6067e3a5235a 100644 --- a/testtools/source/bridgetest/bridgetest.cxx +++ b/testtools/source/bridgetest/bridgetest.cxx @@ -1263,6 +1263,10 @@ sal_Int32 TestBridgeImpl::run( const Sequence< OUString > & rArgs ) bRet = check( raiseException( xLBT ) , "exception test" )&& bRet; bRet = check( raiseOnewayException( xLBT ), "oneway exception test" ) && bRet; + // Check that a dynamic_cast from what is potentially a proxy object does not cause a crash + // (and the choice of TestBridgeImpl as target is rather arbitrary, it is just some type for + // which the dynamic_cast is known to be null): + bRet = (dynamic_cast(xOriginal.get()) == nullptr) && bRet; if (! bRet) { throw RuntimeException( "error: test failed!" ); -- cgit