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

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

commit 1040d136d89c8c64bf4ed2991f2779343c1f09d9
Author: Peter Kovacs <[email protected]>
AuthorDate: Sat Jul 25 10:47:35 2026 +0200

    bridges/msvc_win64: fix the x64 C++/UNO bridge (backport 
origin/windows-amd64)
    
    The x64 bridge only linked; it was never actually exercised through a 
generated
    vtable snippet (the roundtrip test dispatched via uno_Interface directly), 
so
    several real bugs hid until soffice ran.  Adopt the validated windows-amd64
    versions of the matched set:
    
    - call.asm + cpp2uno.cxx: codeSnippet emitted bad machine-code opcodes -- 
0x49
      where the mov [rsp+8],rcx / mov [rsp+16],rdx opcode must be 0x89 (0x49 is 
a
      stray REX prefix, decoding as "and al,8"), so the snippet never homed 
this/args
      and cpp_vtable_call got a garbage this (ad7f763788).  And 
callVirtualMethod used
      .ALLOCSTACK unwind info while adjusting rsp dynamically -> not unwindable 
->
      C++/SEH exceptions could not propagate through it; the reference uses
      .SETFRAME rbp, required for a frame with dynamic stack allocation 
(607903dd38).
    - abi.cxx return_in_hidden_param: the >8-byte-struct case was inverted 
(returned
      "register" instead of "hidden memory pointer"), corrupting every 
struct/exception
      return larger than 8 bytes -- e.g. getAllExtensions' nested Sequences 
(0c2e3065a0).
    - except.cxx: our __type_info helper carried an extra _m_name field, 
shifting the
      mangled name off MSVC's type_info layout (offset 24 vs 16).  Exact-type 
catches
      match by type_info address and worked; cross-DLL BASE-class catches fall 
back to
      name strcmp and read the misplaced field -> 
catch(InteractiveIOException&) never
      matched a thrown InteractiveAugmentedIOException, so getCaughtException's 
rethrow
      escaped uncaught and soffice exited silently after 
CheckExtensionDependencies.
    
    uno2cpp.cxx / abi.hxx / dllinit.cxx / mscx.hxx were already identical to the
    reference and are unchanged.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
    (cherry picked from commit 4c722fde1cbd72735e4d7bc86cb790e6719790b4)
---
 .../source/cpp_uno/msvc_win64_x86-64/abi.cxx       | 10 ++-
 .../source/cpp_uno/msvc_win64_x86-64/call.asm      | 80 ++++++++++--------
 .../source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx   | 23 ++++--
 .../source/cpp_uno/msvc_win64_x86-64/except.cxx    | 96 ++++++++++++++++++----
 4 files changed, 143 insertions(+), 66 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 a1722d4011..a203737a70 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
@@ -66,16 +66,20 @@ bool x86_64::return_in_hidden_param( 
typelib_TypeDescriptionReference *pTypeRef
                 typelib_TypeDescription * pTypeDescr = 0;
                 TYPELIB_DANGER_GET( &pTypeDescr, pTypeRef );
 
-                /* If the struct is larger than 8 bytes, pass it on the stack. 
 */
+                /* 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 false;
+                    return true;
                 }
                 else
                 {
                     TYPELIB_DANGER_RELEASE( pTypeDescr );
-                    return true;
+                    return false;
                 }
             }
 
diff --git a/main/bridges/source/cpp_uno/msvc_win64_x86-64/call.asm 
b/main/bridges/source/cpp_uno/msvc_win64_x86-64/call.asm
index beb2797521..402d7e2319 100644
--- a/main/bridges/source/cpp_uno/msvc_win64_x86-64/call.asm
+++ b/main/bridges/source/cpp_uno/msvc_win64_x86-64/call.asm
@@ -6,16 +6,16 @@
 ; to you under the Apache License, Version 2.0 (the
 ; "License"); you may not use this file except in compliance
 ; with the License.  You may obtain a copy of the License at
-;
+; 
 ;   http://www.apache.org/licenses/LICENSE-2.0
-;
+; 
 ; Unless required by applicable law or agreed to in writing,
 ; software distributed under the License is distributed on an
 ; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 ; KIND, either express or implied.  See the License for the
 ; specific language governing permissions and limitations
 ; under the License.
-;
+; 
 
 
 typelib_TypeClass_VOID equ 0
@@ -51,8 +51,8 @@ EXTERN cpp_vtable_call: PROC
 ; rbp+16 rsp+08 +----------------------------+ -------
 ;               | return address             |
 ; rbp+08 rsp--> +----------------------------+
-;               | old rbp                    |
-; rbp---------> +----------------------------+
+;               | caller's rbp               |
+; rbp---------> +----------------------------+ <------ 16 byte boundary
 ;               | pRegisterReturn memory     |
 ; rbp-08 -----> +----------------------------+
 ;               |                            |
@@ -72,14 +72,14 @@ EXTERN cpp_vtable_call: PROC
 ;
 
 privateSnippetExecutor PROC FRAME
-
        push    rbp
+       .PUSHREG rbp
        mov     rbp, rsp
+       .SETFRAME rbp, 0
        sub     rsp, 48
-       .ALLOCSTACK(48)
        .ENDPROLOG
 
-       ; 4th param: sal_uInt64 *pRegisterReturn
+       ; 4th param: sal_uInt64 *pRegisterReturn 
        lea r9, -8[rbp]
 
        ; 3rd param: sal_Int32 nVtableOffset
@@ -98,7 +98,8 @@ privateSnippetExecutor PROC FRAME
        mov rax, -8[rbp]
        movsd xmm0, qword ptr -8[rbp]
 
-       leave
+       add rsp, 48
+        pop rbp
        ret
 
 privateSnippetExecutor ENDP
@@ -121,7 +122,7 @@ privateSnippetExecutor ENDP
 ; rbp+16 -----> +---------------------------------------------+ -------
 ;               | return address                              |
 ; rbp+08 -----> +---------------------------------------------+
-;               | old rbp                                     |
+;               | caller's rbp                                |
 ; rbp --------> +---------------------------------------------+ <---- 16 byte 
boundary
 ;               | (possible 16 byte alignment placeholder)    |
 ; rbp-08 -----> +---------------------------------------------+
@@ -133,8 +134,9 @@ privateSnippetExecutor ENDP
 callVirtualMethod PROC FRAME
 
        push rbp
+       .PUSHREG rbp
        mov rbp, rsp
-       .ENDPROLOG
+       .SETFRAME rbp, 0
 
        ; Save our register arguments to the shadow space:
        mov 16[rbp], rcx
@@ -142,28 +144,33 @@ callVirtualMethod PROC FRAME
        mov 32[rbp], r8
        mov 40[rbp], r9
 
-       ; We must maintain the stack aligned to a 16 byte boundary:
+       ; nStack rounded to multiple of 2, so the stack is aligned to a 16 byte 
boundary:
        mov eax, 56[rbp]
-       cmp rax, 0
-       je stackIsEmpty
-       mov r11, rax
-       test rax,1
-       jz stackSizeEven
-       sub rsp, 8
-stackSizeEven:
-       mov r10, 48[rbp]
-       shl rax, 3        ; nStack is in units of sal_uInt64, and 
sizeof(sal_uInt64) == 8
-       add rax, r10
+       inc eax
+       shr eax, 1
+       shl eax, 1
+
+       ; if nStack < 4, add (4 - nStack) empty slots to the stack:
+       mov r10d, 4
+       sub r10d, eax
+       js copyStack
+       shl r10, 3
+       sub rsp, r10
 
 copyStack:
+       mov r10, rax
+       shl rax, 3
+       add rax, 48[rbp]
+copyStackLoop:
        sub rax, 8
        push [rax]
-       dec r11
-       jne copyStack
+       dec r10
+       jne copyStackLoop
 
+populateArgumentRegisters:
        ; First 4 args are passed in registers. Floating point args needs to be
-       ; in floating point registers, but those are free for us to clobber
-       ; anyway, and the callee knows where to look, so put each arg in both
+       ; in floating point registers, but those are volatile anyway,
+       ; and the callee knows where to look, so put each arg in both
        ; its general purpose and its floating point register:
        mov rcx, [rsp]
        movsd xmm0, qword ptr [rsp]
@@ -173,11 +180,10 @@ copyStack:
        movsd xmm2, qword ptr 16[rsp]
        mov r9, 24[rsp]
        movsd xmm3, qword ptr 24[rsp]
-       jmp callMethod
 
-stackIsEmpty:
-       sub rsp, 32       ; we still need shadow space
+       .ENDPROLOG
 
+       
 callMethod:
        ; Find the method pointer
        mov rax, 16[rbp]
@@ -188,6 +194,7 @@ callMethod:
        call qword ptr [r10]
 
        mov r10d, 40[rbp]
+       mov r11, 32[rbp]
        cmp r10, typelib_TypeClass_VOID
        je cleanup
        cmp r10, typelib_TypeClass_LONG
@@ -217,30 +224,31 @@ callMethod:
 
        ; 
https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2017
        ; "The same pointer must be returned by the callee in RAX."
-       jmp Lint64
+       jmp cleanup
 
 Lint64:
-       mov 32[rbp], rax
+       mov qword ptr [r11], rax
        jmp cleanup
 
 Lint32:
-       mov 32[rbp], eax
+       mov dword ptr [r11], eax
        jmp cleanup
 
 Lint16:
-       mov 32[rbp], ax
+       mov word ptr [r11], ax
        jmp cleanup
 
 Lint8:
-       mov 32[rbp], al
+       mov byte ptr [r11], al
        jmp cleanup
 
 Lfloat:
-       movsd qword ptr 32[rbp], xmm0
+       movsd qword ptr [r11], xmm0
        jmp cleanup
 
 cleanup:
-       leave
+       lea rsp, 0[rbp]
+       pop rbp
        ret
 
 callVirtualMethod ENDP
diff --git a/main/bridges/source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx 
b/main/bridges/source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx
index 5deb06b112..59f250784c 100644
--- a/main/bridges/source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx
+++ b/main/bridges/source/cpp_uno/msvc_win64_x86-64/cpp2uno.cxx
@@ -1,5 +1,5 @@
 /**************************************************************
- *
+ * 
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -7,16 +7,16 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- *
+ * 
  *   http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
+ * 
  *************************************************************/
 
 
@@ -343,7 +343,7 @@ extern "C" typelib_TypeClass cpp_vtable_call(
 
//==================================================================================================
 extern "C" void privateSnippetExecutor( ... );
 
-int const codeSnippetSize = 44;
+int const codeSnippetSize = 48;
 
 unsigned char * codeSnippet(
     unsigned char * code, sal_Int32 functionIndex, sal_Int32 vtableOffset, 
bool isArgFloat[4])
@@ -366,8 +366,13 @@ unsigned char * codeSnippet(
     //  rsp+08 +----------------------------+ -------
     //         | return address             |
     //  rsp--> +----------------------------+
+    // 
     //
-    //
+
+    // When it doubt about correctness,
+    // uncomment this and disassemble at runtime:
+    // INT 0x3
+    //*p++ = 0xcc;
 
     if (isArgFloat[0])
     {
@@ -377,7 +382,7 @@ unsigned char * codeSnippet(
     else
     {
         // mov QWORD[rsp+8], rcx
-        *p++ = 0x48; *p++ = 0x49; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x08;
+        *p++ = 0x48; *p++ = 0x89; *p++ = 0x4c; *p++ = 0x24; *p++ = 0x08;
     }
 
     if (isArgFloat[1])
@@ -388,7 +393,7 @@ unsigned char * codeSnippet(
     else
     {
         // mov QWORD[rsp+16], rdx
-        *p++ = 0x48; *p++ = 0x49; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
+        *p++ = 0x48; *p++ = 0x89; *p++ = 0x54; *p++ = 0x24; *p++ = 0x10;
     }
 
     if (isArgFloat[2])
@@ -441,7 +446,7 @@ unsigned char * codeSnippet(
     *p++ = (((sal_uIntPtr)(&privateSnippetExecutor)) >> 56) & 0xff;
 
     // jmp r11
-    *p++ = 0x49;
+    *p++ = 0x41;
     *p++ = 0xff;
     *p++ = 0xe3;
 
diff --git a/main/bridges/source/cpp_uno/msvc_win64_x86-64/except.cxx 
b/main/bridges/source/cpp_uno/msvc_win64_x86-64/except.cxx
index 55f2aa4779..98218480ab 100644
--- a/main/bridges/source/cpp_uno/msvc_win64_x86-64/except.cxx
+++ b/main/bridges/source/cpp_uno/msvc_win64_x86-64/except.cxx
@@ -1,5 +1,5 @@
 /**************************************************************
- *
+ * 
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -7,16 +7,16 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- *
+ * 
  *   http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
+ * 
  *************************************************************/
 
 
@@ -47,6 +47,67 @@ using namespace ::std;
 using namespace ::osl;
 using namespace ::rtl;
 
+//##############################################################################
+// Windows's C++ exception  handling is built on top of SEH (Structured 
Exception Handling).
+//
+// SEH documentation:
+// 
https://web.archive.org/web/20060114142024/https://www.microsoft.com/msj/0197/exception/exception.aspx
+//
+// See this excellent article,
+// "Decoding the parameters of a thrown C++ exception (0xE06D7363)"
+// by Raymond Chen:
+// https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
+//
+// Then this one with more details on ExceptionInformation:
+// http://workblog.pilin.name/2014/03/decoding-parameters-of-thrown-c.html
+//
+// Others:
+// https://github.com/icestudent/ontl/blob/master/ntl/nt/exception.hxx
+// https://www.openrce.org/articles/full_view/21
+// https://www.openrce.org/articles/full_view/23
+//
+// For a C++ exception in SEH, on AMD64:
+//
+// +-----------------------------------+            
+-------------------------------------------------------------+
+// |EXCEPTION_POINTERS                 |            |EXCEPTION_RECORD          
                                   |
+// +-----------------------------------+            
+-------------------------------------------------------------+
+// |PEXCEPTION_RECORD  ExceptionRecord;|----------->|DWORD ExceptionCode; // 
== 0xE06D7363 for C++ exception      |
+// |PCONTEXT           ContextRecord;  |            |DWORD ExceptionFlags;     
                                   |
+// +-----------------------------------+            |struct  _EXCEPTION_RECORD 
*ExceptionRecord;                  |
+//                                                  |PVOID ExceptionAddress;   
                                   |
+//                                                  |DWORD NumberParameters; 
// == 4 on AMD64, 3 on i386          |
+//                                                  |ULONG_PTR 
ExceptionInformation[0];                           |
+//               C++ object being thrown <----------|ULONG_PTR 
ExceptionInformation[1];                           |
+//   +----------------------------------------------|ULONG_PTR 
ExceptionInformation[2];                           |
+//   |    HINSTANCE of the EXE/DLL where <----------|ULONG_PTR 
ExceptionInformation[3];                           |
+//   |    where the exception was thrown            |ULONG_PTR 
ExceptionInformation[...];                         |
+//   |                                              |ULONG_PTR 
ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];|
+//   | offset from HINSTANCE                        
+-------------------------------------------------------------+
+//   | to:
+//   |     +------------------------------+
+//   |     |ThrowInfo                     |
+//   |     +------------------------------+
+//   +---->|unsigned int attributes;      |                             
+----------------------------------+
+//         |PMFN   pmfnUnwind;            |                             
|CatchableTypeArray                |
+//         |__int32   pForwardCompat;     | offset from HINSTANCE to:   
+----------------------------------+
+//         |__int32   pCatchableTypeArray;|---------------------------->|int 
nCatchableTypes;              |
+//         +------------------------------+                    
+--------|__int32   arrayOfCatchableTypes[];|
+//                                                             |        
+----------------------------------+
+//        +------------------------+                           |
+//        |CatchableType           |                           |
+//        +------------------------+ offsets from HINSTANCE to |
+//        |unsigned int properties;|<--------------------------+        
+--------------------------------+
+//        |__int32   pType;        |---------+                          
|TypeDescriptor                  |
+//        |PMD    thisDisplacement;|         | offset from HINSTANCE to 
+--------------------------------+
+//        |int    sizeOrOffset;    |         +------------------------->|const 
void * _EH_PTR64 pVFTable;|
+//        |PMFN   copyFunction;    |                                    |void 
* _EH_PTR64   spare;       |
+//        +------------------------+                                    |char 
name[];                    |
+//                                                                      
+--------------------------------+
+//
+//
+//
+//
+
 namespace CPPU_CURRENT_NAMESPACE
 {
 
@@ -117,9 +178,8 @@ class __type_info
 public:
     virtual ~__type_info() throw ();
 
-       inline __type_info( void * m_vtable, const char * m_d_name ) throw ()
-               : _m_vtable( m_vtable )
-               , _m_name( NULL )
+       inline __type_info( void * m_data, const char * m_d_name ) throw ()
+               : _m_data( m_data )
         { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
 
        size_t length() const
@@ -128,8 +188,7 @@ public:
        }
 
 private:
-    void * _m_vtable;
-    char * _m_name;     // cached copy of unmangled name, NULL initially
+    void * _m_data;
     char _m_d_name[1];  // mangled name
 };
 
//__________________________________________________________________________________________________
@@ -340,7 +399,7 @@ RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr 
) throw ()
        , _n2( 0 )
 {
        // a must be
-       OSL_ENSURE( sizeof(sal_Int32) == sizeof(ExceptionType *), "### pointer 
size differs from sal_Int32!" );
+       OSL_ENSURE( sizeof(sal_Int64) == sizeof(ExceptionType *), "### pointer 
size differs from sal_Int64!" );
 
        ::typelib_typedescription_acquire( pTypeDescr );
        this->pTypeDescr = pTypeDescr;
@@ -427,7 +486,7 @@ ExceptionInfos::~ExceptionInfos() throw ()
 #if OSL_DEBUG_LEVEL > 1
        OSL_TRACE( "> freeing exception infos... <\n" );
 #endif
-
+    
        MutexGuard aGuard( _aMutex );
        for ( t_string2PtrMap::const_iterator iPos( _allRaiseInfos.begin() );
           iPos != _allRaiseInfos.end(); ++iPos )
@@ -522,8 +581,8 @@ void mscx_raiseException( uno_Any * pUnoExc, uno_Mapping * 
pUno2Cpp )
 
        // a must be
        OSL_ENSURE(
-        sizeof(sal_Int32) == sizeof(void *),
-        "### pointer size differs from sal_Int32!" );
+        sizeof(sal_Int64) == sizeof(void *),
+        "### pointer size differs from sal_Int64!" );
        RaiseInfo *raiseInfo = ExceptionInfos::getRaiseInfo( pTypeDescr );
        ULONG_PTR arFilterArgs[4];
        arFilterArgs[0] = MSVC_magic_number;
@@ -549,9 +608,9 @@ int mscx_filterCppException(
     // handle only C++ exceptions:
        if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
         return EXCEPTION_CONTINUE_SEARCH;
-
+    
 #if _MSC_VER < 1300 // MSVC -6
-    bool rethrow = (pRecord->NumberParameters < 3 ||
+    bool rethrow = (pRecord->NumberParameters < 4 ||
                     pRecord->ExceptionInformation[ 2 ] == 0);
 #else
     bool rethrow = __CxxDetectRethrow( &pRecord );
@@ -574,7 +633,7 @@ int mscx_filterCppException(
     // rethrow: handle only C++ exceptions:
        if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
         return EXCEPTION_CONTINUE_SEARCH;
-
+    
     if (pRecord->NumberParameters == 4 &&
 //             pRecord->ExceptionInformation[ 0 ] == MSVC_magic_number &&
                pRecord->ExceptionInformation[ 1 ] != 0 &&
@@ -596,7 +655,7 @@ int mscx_filterCppException(
                             baseAddress + pType->_pTypeInfo )->_m_d_name,
                         RTL_TEXTENCODING_ASCII_US ) );
                                OUString aUNOname( toUNOname( aRTTIname ) );
-
+                
                                typelib_TypeDescription * pExcTypeDescr = 0;
                                typelib_typedescription_getByName(
                     &pExcTypeDescr, aUNOname.pData );
@@ -640,7 +699,7 @@ int mscx_filterCppException(
 #endif
                                        typelib_typedescription_release( 
pExcTypeDescr );
                                }
-
+                
                                return EXCEPTION_EXECUTE_HANDLER;
                        }
                }
@@ -660,3 +719,4 @@ int mscx_filterCppException(
 }
 
 #pragma pack(pop)
+

Reply via email to