This is an automated email from the ASF dual-hosted git repository.

leginee pushed a commit to branch win10-msvc-trunk
in repository https://gitbox.apache.org/repos/asf/openoffice.git

commit 10b60aa28b8069703f4df8013150ae795e6dfb54
Author: Peter Kovacs <[email protected]>
AuthorDate: Fri Aug 21 21:11:13 2026 +0200

    cli_ure: two runtime defects in the ported bridge, found by running it
    
    The bridge built and loaded after the syntax port, but the first time the
    CLI bridgetest actually drove data through it, it failed on the very first
    mapping.  Two causes, both introduced by the port and both invisible to the
    compiler.
    
    1. A HANDLE COMPARED AGAINST 0 IS NOT A NULL TEST.
    
       In MC++ a managed reference was a POINTER -- "Object* ret" -- so
       "ret != 0" was an ordinary null check.  In C++/CLI it is a HANDLE, and
       0 is not a null literal for one; for System::Object^ the compiler takes
       the implicit boxing conversion instead and reference-compares against a
       freshly boxed Int32.  That is true for every value of ret, null included.
    
       So this, in getRegisteredInterface:
    
           if (ret != 0)
           {
               WeakReference ^ weakIface = static_cast< WeakReference ^ >( ret 
);
               ret = weakIface->Target;          // ret is null -> NullReference
           }
    
       took the branch on a null ret and dereferenced it.  The bridge caught the
       NullReferenceException, turned it into a BridgeRuntimeError, and
       Mapping_uno2cli swallowed that and left the out slot at zero -- so what
       the caller finally saw was an InvalidOperationException from
       GCHandle::FromIntPtr, three layers away and naming nothing that had gone
       wrong.  It cost a probe in the middle of the function to see that ret was
       null and the branch was taken anyway.
    
       Fifteen sites across the bridge; the guilty ones are the System::Object^
       comparisons.  For a specific handle type -- System::Type^,
       UnoInterfaceProxy^ -- there is no conversion from int, so the compiler
       has to read 0 as null and those were already correct.  All of them now
       say nullptr, which is right in either case.
    
       Note what the compiler does here: it accepts "handle != 0" and silently
       changes what it means.  Nothing warns.  Any MC++ port has this.
    
    2. A SEQUENCE OF BOOLEAN CONVERTED IN NEITHER DIRECTION.
    
       Marshal::Copy has no Boolean[] overload -- byte, char, the integers,
       float, double, IntPtr, no bool.  MC++ handed it one anyway, because it
       would implicitly convert an array of bool to an array of byte.  C++/CLI
       will not, and whoever hit that error during the port made it compile by
       changing the CAST to Byte[] rather than the copy:
    
           Marshal::Copy(safe_cast< cli::array< System::Byte > ^ >(cli_data), 
...)
    
       safe_cast is checked, and bool[] is not castclass-compatible with byte[]
       the way int16[] is with uint16[] -- the CLR's array covariance covers
       signed/unsigned integrals of the same size, not bool.  So every
       sequence<boolean> crossing the bridge threw InvalidCastException, which
       the caller saw as "could not convert sequence element type: boolean".
       The uno->cli direction had the mirror of it, handing the caller a byte[]
       where the signature says bool[].
    
       Both now copy the elements.  Comparing the cast element types before and
       after the port turns this up in one line -- Boolean went missing and Byte
       appeared twice -- and that check is worth repeating for any similar port.
    
    With these the bridgetest bootstraps, maps the component context, and gets
    into the tests proper.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01W7pjcp2sXU1HaUwXT7kc29
---
 main/cli_ure/source/uno_bridge/cli_data.cxx        | 49 +++++++++++++++-------
 main/cli_ure/source/uno_bridge/cli_environment.cxx |  4 +-
 main/cli_ure/source/uno_bridge/cli_proxy.cxx       |  4 +-
 3 files changed, 38 insertions(+), 19 deletions(-)

diff --git a/main/cli_ure/source/uno_bridge/cli_data.cxx 
b/main/cli_ure/source/uno_bridge/cli_data.cxx
index 0bd15c4261..4e3a1a3a89 100644
--- a/main/cli_ure/source/uno_bridge/cli_data.cxx
+++ b/main/cli_ure/source/uno_bridge/cli_data.cxx
@@ -410,7 +410,7 @@ typelib_TypeDescriptionReference* mapCliType(System::Type ^ 
cliType)
             break;
         }
     }
-    if (retVal == NULL)
+    if (retVal == nullptr)
     {
         System::String ^ cliTypeName= cliType->FullName;
         // Void
@@ -456,7 +456,7 @@ typelib_TypeDescriptionReference* mapCliType(System::Type ^ 
cliType)
             }
         }
     }
-    if (retVal == NULL)
+    if (retVal == nullptr)
     {
         OUStringBuffer buf( 128 );
         buf.appendAscii(
@@ -831,7 +831,7 @@ void Bridge::map_to_uno(void * uno_data, System::Object ^ 
cli_data,
                 rtl_uString_release(*(rtl_uString**) uno_data);
 
             *(rtl_uString **)uno_data = 0;
-            if (cli_data == NULL)
+            if (cli_data == nullptr)
             {
                  rtl_uString_new((rtl_uString**) uno_data);
             }
@@ -859,7 +859,7 @@ void Bridge::map_to_uno(void * uno_data, System::Object ^ 
cli_data,
         case typelib_TypeClass_ANY:
         {
             uno_Any * pAny = (uno_Any *)uno_data;
-            if (cli_data == NULL) // null-ref or uninitialized any maps to 
empty any
+            if (cli_data == nullptr) // null-ref or uninitialized any maps to 
empty any
             {
                 if (assign)
                     uno_any_destruct( pAny, 0 );
@@ -1087,10 +1087,10 @@ void Bridge::map_to_uno(void * uno_data, System::Object 
^ cli_data,
                     System::String ^ __s;
                     cli::array< sr::FieldInfo ^ > ^ arFields;
                     __s = mapUnoString(comp_td->ppMemberNames[nPos]);
-                    arFields = cliType != NULL ? cliType->GetFields() : NULL;
+                    arFields = cliType != nullptr ? cliType->GetFields() : 
NULL;
 #endif
                     System::Object ^ val= nullptr;
-                    if (cli_data != NULL)
+                    if (cli_data != nullptr)
                     {
                         sr::FieldInfo ^ aField= cliType->GetField(
                             mapUnoString(comp_td->ppMemberNames[nPos]));
@@ -1125,8 +1125,8 @@ void Bridge::map_to_uno(void * uno_data, System::Object ^ 
cli_data,
                     bool bDefault = ((struct_td != NULL
                                      && struct_td->pParameterizedTypes != NULL
                                      && struct_td->pParameterizedTypes[nPos] 
== sal_True
-                                      && val == NULL)
-                                     || cli_data == NULL) ? true : false;
+                                      && val == nullptr)
+                                     || cli_data == nullptr) ? true : false;
                     switch (member_type->eTypeClass)
                     {
                     case typelib_TypeClass_CHAR:
@@ -1266,7 +1266,7 @@ void Bridge::map_to_uno(void * uno_data, System::Object ^ 
cli_data,
             auto_ptr< rtl_mem > seq;
 
             System::Array ^ ar = nullptr;
-            if (cli_data != NULL)
+            if (cli_data != nullptr)
             {
                 ar = safe_cast< System::Array ^ >(cli_data);
                 sal_Int32 nElements = ar->GetLength(0);
@@ -1281,10 +1281,23 @@ void Bridge::map_to_uno(void * uno_data, System::Object 
^ cli_data,
                                            System::IntPtr(& ((uno_Sequence*) 
seq.get())->elements), nElements);
                         break;
                     case typelib_TypeClass_BOOLEAN:
+                    {
+                        // Marshal::Copy has no Boolean[] overload.  MC++ got
+                        // away with handing it one because it would implicitly
+                        // convert an array of bool to an array of byte;
+                        // C++/CLI will not, and a safe_cast to Byte[] throws,
+                        // because bool[] and byte[] are not castclass
+                        // compatible the way int16[] and uint16[] are.  Copy
+                        // the elements instead.
                         seq = seq_allocate(nElements, sizeof (sal_Bool));
-                        sri::Marshal::Copy(safe_cast< cli::array< System::Byte 
> ^ >(cli_data), 0,
-                                           System::IntPtr(& ((uno_Sequence*) 
seq.get())->elements), nElements);
+                        cli::array< System::Boolean > ^ arBool =
+                            safe_cast< cli::array< System::Boolean > ^ 
>(cli_data);
+                        sal_Bool * pDest = (sal_Bool *)
+                            & ((uno_Sequence*) seq.get())->elements;
+                        for (sal_Int32 i = 0; i < nElements; i++)
+                            pDest[i] = arBool[i] ? sal_True : sal_False;
                         break;
+                    }
                     case typelib_TypeClass_BYTE:
                         seq = seq_allocate( nElements, sizeof (sal_Int8) );
                     sri::Marshal::Copy(safe_cast< cli::array< System::Byte > ^ 
>(cli_data), 0,
@@ -1442,10 +1455,10 @@ void Bridge::map_to_uno(void * uno_data, System::Object 
^ cli_data,
             if (assign)
             {
                 uno_Interface * p = *(uno_Interface **)uno_data;
-                if (0 != p)
+                if (nullptr != p)
                     (*p->release)( p );
             }
-            if (0 == cli_data) // null-ref
+            if (nullptr == cli_data) // null-ref
             {
                 *(uno_Interface **)uno_data = 0;
             }
@@ -1773,8 +1786,14 @@ void Bridge::map_to_cli(
         }
         case typelib_TypeClass_BOOLEAN:
         {
-            cli::array< System::Byte > ^ arBool = gcnew cli::array< 
System::Byte >( nElements );
-            sri::Marshal::Copy( System::IntPtr( (void*) &seq->elements ), 
arBool, 0, nElements);
+            // The element type has to be Boolean -- the caller gets a bool[].
+            // Marshal::Copy cannot fill one (see the other direction), so copy
+            // the elements.
+            cli::array< System::Boolean > ^ arBool =
+                gcnew cli::array< System::Boolean >( nElements );
+            sal_Bool const * pSrc = (sal_Bool const *) &seq->elements;
+            for (sal_Int32 i = 0; i < nElements; i++)
+                arBool[i] = (pSrc[i] != sal_False);
             *cli_data= arBool;
             break;
         }
diff --git a/main/cli_ure/source/uno_bridge/cli_environment.cxx 
b/main/cli_ure/source/uno_bridge/cli_environment.cxx
index 275ed9ca04..8d6c513dca 100644
--- a/main/cli_ure/source/uno_bridge/cli_environment.cxx
+++ b/main/cli_ure/source/uno_bridge/cli_environment.cxx
@@ -127,13 +127,13 @@ System::Object ^ 
Cli_environment::getRegisteredInterface(System::String ^ oid,
         oid = createKey(oid, type);
         ret = m_objects[ oid ];
     }
-    if (ret != 0)
+    if (ret != nullptr)
     {
         System::WeakReference ^ weakIface =
             static_cast< System::WeakReference ^ >( ret );
         ret = weakIface->Target;
     }
-    if (ret == 0)
+    if (ret == nullptr)
         m_objects->Remove( oid );
     return ret;
 }
diff --git a/main/cli_ure/source/uno_bridge/cli_proxy.cxx 
b/main/cli_ure/source/uno_bridge/cli_proxy.cxx
index 459f7bf706..a4746b98b4 100644
--- a/main/cli_ure/source/uno_bridge/cli_proxy.cxx
+++ b/main/cli_ure/source/uno_bridge/cli_proxy.cxx
@@ -290,7 +290,7 @@ bool UnoInterfaceProxy::CanCastTo(System::Type ^ fromType,
                 UnoInterfaceProxy ^ proxy =
                     static_cast< UnoInterfaceProxy ^ >(
                         srr::RemotingServices::GetRealProxy( obj ) );
-                OSL_ASSERT( 0 != proxy->findInfo( fromType ) );
+                OSL_ASSERT( nullptr != proxy->findInfo( fromType ) );
                 m_listAdditionalProxies->Add( proxy );
                 m_nlistAdditionalProxies = m_listAdditionalProxies->Count;
                 OSL_ASSERT(nullptr != findInfo( fromType ) );
@@ -438,7 +438,7 @@ srrm::IMessage ^ UnoInterfaceProxy::Invoke(srrm::IMessage ^ 
callmsg)
 
         System::Type ^ typeBeingCalled = loadCliType(sTypeName);
         UnoInterfaceInfo ^ info = findInfo( typeBeingCalled );
-        OSL_ASSERT( 0 != info );
+        OSL_ASSERT( nullptr != info );
 
         // ToDo do without string conversion, a OUString is not needed here
         // get the type description of the call

Reply via email to