Bug 147377 - Reimplement SbiDllMgr::Call using libffi
Summary: Reimplement SbiDllMgr::Call using libffi
Status: ASSIGNED
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: BASIC (show other bugs)
Version:
(earliest affected)
unspecified
Hardware: All All
: medium enhancement
Assignee: Samuel Adesola
URL:
Whiteboard:
Keywords: difficultyInteresting, easyHack
Depends on:
Blocks: Dev-related
  Show dependency treegraph
 
Reported: 2022-02-11 15:15 UTC by Mike Kaganski
Modified: 2024-10-12 06:44 UTC (History)
6 users (show)

See Also:
Crash report or crash signature:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Kaganski 2022-02-11 15:15:16 UTC
Currently Basic's Declare statement [1] is implemented in basic/source/runtime/dllmgr*.cxx using home-grown marshaling code [2]. This poses several problems:

1. The code is platform-specific (requires separate maintenance per platform), with much duplication.
2. It has limitation to 20 arguments (see [3]).
3. Calls using non-default calling convention are not implemented (and would require much work) - so e.g. CDecl keyword is not implemented on Win32, where it makes sense.

There is libffi [4] that solves exactly this problem. Using it instead of home-grown code to call external DLL functions would allow to unify the code across platforms (and implement it where it isn't implemented); avoid any argument count limitations; define calling convention.

The library uses MIT license; it is already used in LO codebase (it is a requirement for Python), so it only needs to be linked to Library_sb to be usable there. Then the code could look similar to

>   std::vector<ffi_type*>arg_types;
>   std::vector<void*>arg_values;
>   std::vector<char> blob;
>   if (arguments)
>   {
>       arg_types.reserve(arguments->Count());
>       arg_values.reserve(arguments->Count());
>       blob.reserve(arguments->Count() * 8);
>
>       for (sal_uInt32 i = 1; i < arguments->Count(); ++i)
>       {
>           // Put argument values to blob, store pointers to them
>           // in arg_values, and their types in arg_types
>       }
>   }
>
>   ffi_type* ret_t = SbxDataType_to_ffi_type(result.GetType());
>   ffi_abi eAbi = GetAbi(); // e.g., FFI_DEFAULT_ABI or FFI_MS_CDECL
>
>   // Prepare the ffi_cif structure.
>   ffi_cif cif;
>   if (ffi_status status = ffi_prep_cif(&cif, eAbi, 2, ret_t, arg_types.data());
>       status != FFI_OK)
>   {
>       // Handle the ffi_status error.
>   }
>
>   // Invoke the function.
>   ffi_arg retval;
>   ffi_call(&cif, FFI_FN(proc.proc), &retval, arg_values.data());
>   // ...

(sketched after [5]).

[1] https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03090403.html
[2] https://opengrok.libreoffice.org/search?&defs=SbiDllMgr%3A%3ACall&project=core
[3] https://ask.libreoffice.org/t/passing-arrays-in-basic-works-with-excel-error-73-in-libreoffice/48267
[4] https://sourceware.org/libffi/
[5] https://linux.die.net/man/3/ffi_call
Comment 1 Roman Kuznetsov 2023-07-09 08:32:17 UTC
Set to NEW

It looks like EasyHack
Comment 2 Samuel Adesola 2024-10-11 19:04:57 UTC
I submitted a WiP patch to this: https://gerrit.libreoffice.org/c/core/+/174826

Following the code pointer in https://bugs.documentfoundation.org/show_bug.cgi?id=147377 to change to libffi. I don't know if I am in the right direction. I couln't figure out how to add libffi to the Library_sb in the basic folder. I saw libffi is conditionally declared in multiple make files in external/python3.