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
commit adce10bba5577426ee4829485de8508d0c6fd41c Author: Jim Jagielski <[email protected]> AuthorDate: Mon Aug 3 12:21:45 2026 -0400 Fix regressions and gaps found reviewing the arm64 C++-UNO bridge hardening --- .../source/cpp_uno/s5abi_macosx_aarch64/abi.cxx | 8 +++- .../source/cpp_uno/s5abi_macosx_aarch64/call.s | 2 +- .../source/cpp_uno/s5abi_macosx_aarch64/except.cxx | 51 +++++++++++++++++++--- .../cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx | 5 ++- main/solenv/bin/addsym-macosx.sh | 5 +++ main/solenv/src/component.map | 12 +++++ .../com/sun/star/comp/bridge/TestComponent.java | 43 ++++++++++++++++++ .../source/bridgetest/cli/cli_cs_testobj.cs | 43 ++++++++++++++++++ 8 files changed, 158 insertions(+), 11 deletions(-) diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx index d99ee651ee..486e5fd466 100644 --- a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/abi.cxx @@ -124,6 +124,9 @@ bool collectHfa( typelib_TypeDescriptionReference *pTypeRef, HfaKind &rKind, int const typelib_CompoundTypeDescription *pComp = reinterpret_cast<const typelib_CompoundTypeDescription*>( pTypeDescr ); + // rCount is cumulative over the whole recursion, so remember where + // this aggregate started in order to size-check it below. + const int nCountAtEntry = rCount; bool bOk = true; // Flatten base class first (its members precede ours in layout). @@ -138,8 +141,11 @@ bool collectHfa( typelib_TypeDescriptionReference *pTypeRef, HfaKind &rKind, int if ( bOk ) { + // Reject anything the elements do not tile exactly: only the + // elements contributed by THIS aggregate count towards its size. sal_Int32 elementSize = rKind == HFA_FLOAT ? 4 : 8; - bOk = pTypeDescr->nSize == rCount * elementSize; + bOk = pTypeDescr->nSize == + ( rCount - nCountAtEntry ) * elementSize; for ( sal_Int32 i = 0; bOk && i < pComp->nMembers; ++i ) bOk = pComp->pMemberOffsets[i] % elementSize == 0; } diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s index 90994778d1..d0f6388ea7 100644 --- a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/call.s @@ -162,7 +162,7 @@ _privateSnippetExecutor: add x3, sp, #80 // fpreg mov x4, x17 // ovrflw mov x5, x8 // pIndirectReturn (x8 indirect-result reg) - add x6, sp, #144 // pRegisterReturn (16-byte buffer) + add x6, sp, #144 // pRegisterReturn (32-byte buffer) bl _cpp_vtable_call cmp w0, #0x100 // RETURN_KIND_HFA_FLOAT diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx index 7d920cf975..82ee649b72 100644 --- a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx @@ -75,7 +75,11 @@ ObservedRttiMap & observedRttis() return map; } -Mutex & observedRttisMutex() +// Guards BOTH thrownTypes() and observedRttis(). Every access to either map +// must hold this one mutex; they are plain hash_maps, so an insertion racing a +// find or erase is undefined behaviour. RTTI::m_mutex may be held while +// acquiring this one (see RTTI::getRTTI), never the other way round. +Mutex & exceptionMapsMutex() { static Mutex mutex; return mutex; @@ -160,7 +164,7 @@ type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THR MutexGuard guard( m_mutex ); { - MutexGuard observedGuard( observedRttisMutex() ); + MutexGuard observedGuard( exceptionMapsMutex() ); ObservedRttiMap::const_iterator observed( observedRttis().find( unoName ) ); if ( observed != observedRttis().end() ) return observed->second; @@ -191,7 +195,17 @@ type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THR m_rttis.insert( t_rtti_map::value_type( unoName, rtti ) ); } else + { + // Unlike the gcc3_* bridges this one does NOT synthesise a + // __class_type_info when the lookup fails. Hand-built type_info + // objects are not reliably matched by libc++abi's throw/catch + // machinery, so a miss is reported instead of silently producing an + // exception that no handler can catch. Lookup relies on the + // typeinfo actually being exported: see the _ZTI*/_ZTS* entries in + // solenv/src/component.map and the typeinfo carve-out in + // solenv/bin/addsym-macosx.sh. rtti = 0; + } } else { @@ -206,7 +220,7 @@ static void deleteException( void * pExc ) { typelib_TypeDescription * pTD = 0; { - MutexGuard guard( observedRttisMutex() ); + MutexGuard guard( exceptionMapsMutex() ); ThrownTypes::iterator i = thrownTypes().find( pExc ); if ( i != thrownTypes().end() ) { @@ -236,6 +250,17 @@ void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) OUString typeName( *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ) ); + // Every UNO exception derives from com.sun.star.uno.Exception, whose first + // member is the Message string. Keep a copy: if the throw below cannot be + // completed we substitute a RuntimeException, and without this the original + // diagnostic would be lost silently. + OUString message; + if ( pUnoExc->pData != 0 && + *reinterpret_cast< rtl_uString * const * >( pUnoExc->pData ) != 0 ) + { + message = *reinterpret_cast< OUString const * >( pUnoExc->pData ); + } + { // construct cpp exception object typelib_TypeDescription * pTypeDescr = 0; @@ -243,9 +268,13 @@ void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) OSL_ASSERT( pTypeDescr ); if (! pTypeDescr) { + // NOTE: pUnoExc is deliberately left alone here. Destructing an any + // whose type description cannot be resolved is not safe, so this path + // leaks it rather than risking a null dereference. It only fires if + // the type system has already lost the type being thrown. throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM("cannot get typedescription for type ") ) + - *reinterpret_cast< OUString const * >( &pUnoExc->pType->pTypeName ), + typeName + OUString( RTL_CONSTASCII_USTRINGPARAM(": ") ) + message, Reference< XInterface >() ); } @@ -258,14 +287,22 @@ void raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp ) OSL_ENSURE( rtti, "### no rtti for throwing exception!" ); if (! rtti) { + // Undo everything done above: the payload was constructed into the + // __cxa buffer, so it has to be destructed before the buffer is + // released, and raiseException still owes its caller the destruction + // of the incoming any. + ::uno_destructData( pCppExc, pTypeDescr, cpp_release ); + __cxa_free_exception( pCppExc ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + ::uno_any_destruct( pUnoExc, 0 ); throw RuntimeException( OUString( RTL_CONSTASCII_USTRINGPARAM("no rtti for type ") ) + - typeName, + typeName + OUString( RTL_CONSTASCII_USTRINGPARAM(": ") ) + message, Reference< XInterface >() ); } { - MutexGuard guard( Mutex::getGlobalMutex() ); + MutexGuard guard( exceptionMapsMutex() ); typelib_typedescription_acquire( pTypeDescr ); thrownTypes()[pCppExc] = pTypeDescr; } @@ -285,7 +322,7 @@ void fillUnoException( typelib_TypeDescription * pExcTypeDescr = 0; OUString unoName( toUNOname( type.name() ) ); { - MutexGuard guard( Mutex::getGlobalMutex() ); + MutexGuard guard( exceptionMapsMutex() ); observedRttis()[unoName] = const_cast<std::type_info *>( &type ); } typelib_typedescription_getByName( &pExcTypeDescr, unoName.pData ); diff --git a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx index 41c1bc3048..ca5ec8adfd 100644 --- a/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx +++ b/main/bridges/source/cpp_uno/s5abi_macosx_aarch64/uno2cpp.cxx @@ -82,9 +82,10 @@ static void callVirtualMethod(void * pThis, sal_uInt32 nVtableIndex, fprintf( stderr, "\nFPR's (%d): ", nFPR ); for ( unsigned int i = 0; i < nFPR; ++i ) fprintf( stderr, "%f, ", pFPR[i] ); - fprintf( stderr, "\nStack (%d): ", nStack ); + // The overflow area is a packed byte image, not an array of words. + fprintf( stderr, "\nStack (%d bytes): ", nStack ); for ( unsigned int i = 0; i < nStack; ++i ) - fprintf( stderr, "0x%lx, ", pStack[i] ); + fprintf( stderr, "%02x ", pStack[i] ); fprintf( stderr, "\n" ); } #endif diff --git a/main/solenv/bin/addsym-macosx.sh b/main/solenv/bin/addsym-macosx.sh index 604440a5b5..ec1ca18332 100755 --- a/main/solenv/bin/addsym-macosx.sh +++ b/main/solenv/bin/addsym-macosx.sh @@ -44,5 +44,10 @@ s#$#$#' | tr '\n' '|' | sed "s#|\$##" >$2 # Please note that the awk expression expects to get the output of 'nm -gx'! # On Panther we have to filter out symbols with a value "1f" otherwise external # symbols will erroneously be added to the generated export symbols list file. +# Typeinfo and typeinfo-name symbols (__ZTI*, __ZTS*) are exempt from that +# filter: they have vague linkage and legitimately carry the same value, and +# the macOS/arm64 C++-UNO bridge resolves exception typeinfo via dlsym(), so +# dropping them would silently degrade UNO exceptions to RuntimeExceptions. +# See solenv/src/component.map. awk -v SYMBOLSREGEXP="`cat $2`" ' match ($6,SYMBOLSREGEXP) > 0 && $6 !~ /_GLOBAL_/ { if (($2 != 1) && (($2 != "1f") || ($6 ~ /^__ZT[IS]/))) print $6 }' diff --git a/main/solenv/src/component.map b/main/solenv/src/component.map index aecd1e1ffe..21ff867ffc 100644 --- a/main/solenv/src/component.map +++ b/main/solenv/src/component.map @@ -18,6 +18,18 @@ # under the License. # ############################################################### +# NOTE: the _ZTI*/_ZTS* entries below are deliberately not platform-specific. +# A version script that hides typeinfo and typeinfo-name symbols breaks C++ +# across library boundaries: type_info objects have vague linkage, so hiding +# them gives each library its own copy and cross-library "catch" and +# "dynamic_cast" then fail to match. Exporting them restores the one-definition +# behaviour that libraries without a version script already have. +# +# The macOS/arm64 C++-UNO bridge additionally depends on this: it resolves +# exception typeinfo with dlsym() rather than synthesising it, so an unexported +# _ZTI symbol degrades a UNO exception into a RuntimeException. See +# bridges/source/cpp_uno/s5abi_macosx_aarch64/except.cxx (RTTI::getRTTI) and +# solenv/bin/addsym-macosx.sh. UDK_3_0_0 { global: component_getImplementationEnvironment; diff --git a/main/testtools/com/sun/star/comp/bridge/TestComponent.java b/main/testtools/com/sun/star/comp/bridge/TestComponent.java index 0b54a6e650..e64969b8d0 100644 --- a/main/testtools/com/sun/star/comp/bridge/TestComponent.java +++ b/main/testtools/com/sun/star/comp/bridge/TestComponent.java @@ -44,6 +44,11 @@ import test.testtools.bridgetest.SmallStruct; import test.testtools.bridgetest.MediumStruct; import test.testtools.bridgetest.BigStruct; import test.testtools.bridgetest.AllFloats; +import test.testtools.bridgetest.TwoFloats; +import test.testtools.bridgetest.ThreeDoubles; +import test.testtools.bridgetest.MixedFloatLong; +import test.testtools.bridgetest.OneByte; +import test.testtools.bridgetest.ThreeLongs; import test.testtools.bridgetest.XBridgeTest; import test.testtools.bridgetest.XBridgeTest2; import test.testtools.bridgetest.XCurrentContextChecker; @@ -488,10 +493,48 @@ public class TestComponent { return i_Struct; } + public TwoFloats echoTwoFloats( TwoFloats i_Struct) throws com.sun.star.uno.RuntimeException { + return i_Struct; + } + + public ThreeDoubles echoThreeDoubles( ThreeDoubles i_Struct) throws com.sun.star.uno.RuntimeException { + return i_Struct; + } + + public MixedFloatLong echoMixedFloatLong( MixedFloatLong i_Struct) throws com.sun.star.uno.RuntimeException { + return i_Struct; + } + + public OneByte echoOneByte( OneByte i_Struct) throws com.sun.star.uno.RuntimeException { + return i_Struct; + } + + public ThreeLongs echoThreeLongs( ThreeLongs i_Struct) throws com.sun.star.uno.RuntimeException { + return i_Struct; + } + public int testPPCAlignment( long l1, long l2, int i1, long l3, int i2 ) throws com.sun.star.uno.RuntimeException { return i2; } + public long testPackedStack( long a0, long a1, long a2, long a3, long a4, long a5, long a6, + byte b, byte c, short s, int l, byte d, long h ) + throws com.sun.star.uno.RuntimeException + { + return ((((long)b) << 56) | + (((long)(c & 0xff)) << 48) | + (((long)(s & 0xffff)) << 32) | + (((long)l) & 0xffffffffL)) ^ + (((long)d) << 24) ^ h; + } + + public double testFpStack( double a0, double a1, double a2, double a3, double a4, + double a5, double a6, double a7, float f8, double d9 ) + throws com.sun.star.uno.RuntimeException + { + return (double)f8 + d9; + } + // Attributes public boolean getBool() throws com.sun.star.uno.RuntimeException { return _bool; diff --git a/main/testtools/source/bridgetest/cli/cli_cs_testobj.cs b/main/testtools/source/bridgetest/cli/cli_cs_testobj.cs index ad4caf22f4..dc1ed62517 100644 --- a/main/testtools/source/bridgetest/cli/cli_cs_testobj.cs +++ b/main/testtools/source/bridgetest/cli/cli_cs_testobj.cs @@ -240,11 +240,54 @@ public class BridgeTestObject : WeakBase, XRecursiveCall, XBridgeTest2 return arg; } + public TwoFloats echoTwoFloats(/*[in]*/TwoFloats arg) + { + return arg; + } + + public ThreeDoubles echoThreeDoubles(/*[in]*/ThreeDoubles arg) + { + return arg; + } + + public MixedFloatLong echoMixedFloatLong(/*[in]*/MixedFloatLong arg) + { + return arg; + } + + public OneByte echoOneByte(/*[in]*/OneByte arg) + { + return arg; + } + + public ThreeLongs echoThreeLongs(/*[in]*/ThreeLongs arg) + { + return arg; + } + public int testPPCAlignment( long l1, long l2, int i1, long l3, int i2 ) { return i2; } + // UNO byte maps to the unsigned System.Byte here, so the signed terms are + // recovered with an sbyte cast to match the other language bindings. + public long testPackedStack( long a0, long a1, long a2, long a3, long a4, long a5, long a6, + byte b, byte c, short s, int l, byte d, long h ) + { + return ((((long)(sbyte)b) << 56) | + (((long)c) << 48) | + (((long)(ushort)s) << 32) | + ((long)(uint)l)) ^ + (((long)(sbyte)d) << 24) ^ h; + } + + public double testFpStack( double a0, double a1, double a2, double a3, double a4, + double a5, double a6, double a7, float f8, double d9 ) + { + return (double)f8 + d9; + } + // Attributes public bool Bool {
