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
