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
