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 99b7d233cb2e868552d0897dafaa98b5dfe1fd76
Author: Peter Kovacs <[email protected]>
AuthorDate: Sun Aug 23 00:02:13 2026 +0200

    mscx_uno: every UNO struct is returned through a hidden pointer
    
    return_in_hidden_param decided struct returns by size -- nSize > 8 meant a
    hidden pointer, anything smaller meant a register.  The size test itself is
    wrong.  MSVC returns a class in RAX only when it is a POD of 1/2/4/8 bytes,
    and every struct cppumaker emits has user-declared constructors, which makes
    it non-trivial and therefore always returned indirectly, at any size.
    
    So for a <=8-byte struct the bridge passed (this, &arg) where the callee
    expected (this, retptr, &arg).  Arguments shifted by one, r8 held garbage,
    and the first such call took an access violation:
    
        cppobj_uno!bridge_object::Test_Impl::echoTwoFloats:
          movsd xmm0, mmword ptr [r8]   ds:0fffffff`fffffff0=????
    
    Established by disassembly rather than from the ABI documentation --
    echoOneByte (1 byte), echoTwoFloats (8) and echoBigStruct (64) are all
    rcx=this, rdx=hidden return, r8=&arg, writing the result through [rdx] and
    returning it in rax.  Note MSVC puts "this" first and the sret second, the
    opposite of the Itanium ABI.
    
    The size rule hid this: every struct bridgetest had echoed before
    echoTwoFloats -- SmallStruct 16B, MediumStruct 32B, BigStruct 64B, AllFloats
    16B -- is over 8 bytes and took the correct path.  MixedFloatLong (8B) and
    OneByte (1B) sat right behind it.
    
    bridgetest now passes end to end on x64: "### test succeeded!".
    
    This supersedes the nSize>8 form introduced in 0c2e3065a0, which corrected
    an inversion but kept the size test.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01VrM7EMKgiuyVcCUe9nSbZR
---
 .../source/cpp_uno/msvc_win64_x86-64/abi.cxx       | 34 +++++++++-------------
 1 file changed, 14 insertions(+), 20 deletions(-)

diff --git a/main/bridges/source/cpp_uno/msvc_win64_x86-64/abi.cxx 
b/main/bridges/source/cpp_uno/msvc_win64_x86-64/abi.cxx
index a203737a70..af6981bec8 100644
--- a/main/bridges/source/cpp_uno/msvc_win64_x86-64/abi.cxx
+++ b/main/bridges/source/cpp_uno/msvc_win64_x86-64/abi.cxx
@@ -62,26 +62,20 @@ bool x86_64::return_in_hidden_param( 
typelib_TypeDescriptionReference *pTypeRef
             return true;
         case typelib_TypeClass_STRUCT:
         case typelib_TypeClass_EXCEPTION:
-            {
-                typelib_TypeDescription * pTypeDescr = 0;
-                TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
-
-                /* A struct is returned in a register only when its size is
-                 * 1/2/4/8 bytes; otherwise (here: > 8) it is returned via a
-                 * hidden pointer (in memory).  This logic was inverted, which
-                 * corrupted struct/exception return marshalling on x64 — e.g.
-                 * getAllExtensions returning nested Sequences (ref 
0c2e3065a0). */
-                if ( pTypeDescr->nSize > 8 )
-                {
-                    TYPELIB_DANGER_RELEASE( pTypeDescr );
-                    return true;
-                }
-                else
-                {
-                    TYPELIB_DANGER_RELEASE( pTypeDescr );
-                    return false;
-                }
-            }
+            /* MSVC returns a class/struct in RAX only when it is a POD of
+             * 1/2/4/8 bytes.  Every UNO struct cppumaker emits has
+             * user-declared constructors, which makes it non-trivial, so MSVC
+             * always returns one through a hidden pointer -- regardless of
+             * size.  Verified by disassembling cppobj.uno.dll: echoOneByte
+             * (1 byte), echoTwoFloats (8) and echoBigStruct (64) are all
+             * (rcx=this, rdx=hidden return, r8=&arg), writing the result
+             * through [rdx] and returning it in rax.
+             *
+             * Sizing this on nSize > 8 left every <=8-byte struct return one
+             * argument short: the bridge passed (this, &arg) where the callee
+             * expected (this, retptr, &arg), so r8 held garbage and the first
+             * such call -- echoTwoFloats -- took an access violation. */
+            return true;
 
         default:
 #if OSL_DEBUG_LEVEL > 1

Reply via email to