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
     {

Reply via email to