25#include <osl/thread.h>
26#include <osl/security.hxx>
27#include <osl/file.hxx>
28#include <osl/mutex.hxx>
30#include <rtl/ustring.hxx>
33#include <typelib/typedescription.hxx>
37#include <unordered_map>
46#define WIN32_LEAN_AND_MEAN
49#error Unsupported platform
52#if defined USE_DOUBLE_MMAP
56#if defined MACOSX && defined __aarch64__
64extern "C" void * allocExec(
65 SAL_UNUSED_PARAMETER rtl_arena_type *, sal_Size * size)
69#if defined FREEBSD || defined NETBSD || defined OPENBSD || defined DRAGONFLY || defined HAIKU
79#error Unsupported platform
86 nullptr,
n, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON | MAP_JIT, -1,
88 if (
p != MAP_FAILED) {
93 SAL_INFO(
"bridges.osx",
"mmap failed with " << e);
104 nullptr,
n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1,
106 if (
p == MAP_FAILED) {
109 else if (mprotect (
p,
n, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
118 p = VirtualAlloc(
nullptr,
n, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
126extern "C" void freeExec(
127 SAL_UNUSED_PARAMETER rtl_arena_type *,
void * address, sal_Size size)
130 munmap(address, size);
133 VirtualFree(address, 0, MEM_RELEASE);
137#if defined MACOSX && defined __aarch64__
138struct JitMemoryProtectionGuard {
139 JitMemoryProtectionGuard() { pthread_jit_write_protect_np(0); }
140 ~JitMemoryProtectionGuard() { pthread_jit_write_protect_np(1); }
147 public std::vector<Block>
182 typelib_InterfaceTypeDescription * type, sal_Int32 offset);
184 std::unordered_map< OUString, sal_Int32 >
m_map;
188 typelib_InterfaceTypeDescription * type, sal_Int32 offset)
190 OUString
name(
type->aBase.pTypeName);
192 for (sal_Int32
i = 0;
i <
type->nBaseTypes; ++
i) {
193 offset = calculate(
type->ppBaseTypes[
i], offset);
203VtableFactory::VtableFactory(): m_arena(
205 "bridges::cpp_uno::shared::VtableFactory",
207 0, nullptr, allocExec, freeExec, 0))
210 throw std::bad_alloc();
216 std::scoped_lock guard(
m_mutex);
217 for (
const auto& rEntry :
m_map) {
218 for (sal_Int32 j = 0; j < rEntry.second.count; ++j) {
227 typelib_InterfaceTypeDescription * type)
229 OUString
name(
type->aBase.pTypeName);
230 std::scoped_lock guard(
m_mutex);
237 vtables.
count =
static_cast< sal_Int32
>(blocks.size());
239 for (sal_Int32 j = 0; j < vtables.
count; ++j) {
240 vtables.
blocks[j] = blocks[j];
248#ifdef USE_DOUBLE_MMAP
252 std::size_t
pagesize = sysconf(_SC_PAGESIZE);
257 block.start = block.exec = rtl_arena_alloc(
m_arena, &block.size);
258 if (block.start !=
nullptr) {
262 osl::Security aSecurity;
263 OUString strDirectory;
264 OUString strURLDirectory;
265 if (aSecurity.getHomeDir(strURLDirectory))
266 osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory);
268 for (
int i = strDirectory.isEmpty() ? 1 : 0; i < 2; ++i)
270 if (strDirectory.isEmpty())
271 strDirectory =
"/tmp";
273 strDirectory +=
"/.execoooXXXXXX";
275 std::unique_ptr<char[]> tmpfname(
new char[aTmpName.getLength()+1]);
276 strncpy(tmpfname.get(), aTmpName.getStr(), aTmpName.getLength()+1);
278 if ((block.fd = mkstemp(tmpfname.get())) == -1)
279 fprintf(stderr,
"mkstemp(\"%s\") failed: %s\n", tmpfname.get(), strerror(errno));
284 unlink(tmpfname.get());
286#if defined(HAVE_POSIX_FALLOCATE)
287 int err = posix_fallocate(block.fd, 0, block.size);
289 int err = ftruncate(block.fd, block.size);
293#if defined(HAVE_POSIX_FALLOCATE)
294 SAL_WARN(
"bridges",
"posix_fallocate failed with code " << err);
296 SAL_WARN(
"bridges",
"truncation of executable memory area failed with code " << err);
302 block.start = mmap(
nullptr, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0);
303 if (block.start== MAP_FAILED) {
304 block.start =
nullptr;
306 block.exec = mmap(
nullptr, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
307 if (block.exec == MAP_FAILED) {
308 block.exec =
nullptr;
312 if (block.start && block.exec && block.fd != -1)
317 strDirectory.clear();
319 return (block.start !=
nullptr && block.exec !=
nullptr);
324 if (block.fd == -1 && block.start == block.exec && block.start !=
nullptr)
325 rtl_arena_free(
m_arena, block.start, block.size);
328 if (block.start) munmap(block.start, block.size);
329 if (block.exec) munmap(block.exec, block.size);
330 if (block.fd != -1)
close(block.fd);
338 return block.
start !=
nullptr;
348 typelib_InterfaceTypeDescription * type, sal_Int32 vtableNumber,
349 typelib_InterfaceTypeDescription * mostDerived,
bool includePrimary)
const
352#if defined MACOSX && defined __aarch64__
353 JitMemoryProtectionGuard guard;
355 if (includePrimary) {
360 throw std::bad_alloc();
364 block.
start, slotCount, vtableNumber, mostDerived);
365 unsigned char * codeBegin =
366 reinterpret_cast< unsigned char *
>(slots);
367 unsigned char *
code = codeBegin;
368 sal_Int32 vtableOffset = blocks.size() *
sizeof (
Slot *);
369 for (typelib_InterfaceTypeDescription
const * type2 =
type;
370 type2 !=
nullptr; type2 = type2->pBaseTypeDescription)
375 reinterpret_cast<sal_uIntPtr
>(block.
exec) -
reinterpret_cast<sal_uIntPtr
>(block.
start),
383#ifdef USE_DOUBLE_MMAP
388 blocks.push_back(block);
395 for (sal_Int32
i = 0;
i <
type->nBaseTypes; ++
i) {
397 blocks, baseOffset,
type->ppBaseTypes[
i],
398 vtableNumber + (
i == 0 ? 0 : 1), mostDerived,
i != 0);
std::unordered_map< OUString, sal_Int32 > m_map
BaseOffset(typelib_InterfaceTypeDescription *type)
sal_Int32 calculate(typelib_InterfaceTypeDescription *type, sal_Int32 offset)
sal_Int32 getFunctionOffset(OUString const &name) const
const GuardedBlocks & operator=(const GuardedBlocks &)=delete
VtableFactory const & m_factory
GuardedBlocks(VtableFactory const &factory)
GuardedBlocks(const GuardedBlocks &)=delete
Hand out vtable structures for interface type descriptions.
bool createBlock(Block &block, sal_Int32 slotCount) const
const Vtables & getVtables(typelib_InterfaceTypeDescription *type)
Given an interface type description, return its corresponding vtable structure.
sal_Int32 createVtables(GuardedBlocks &blocks, BaseOffset const &baseOffset, typelib_InterfaceTypeDescription *type, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *mostDerived, bool includePrimary) const
static void flushCode(unsigned char const *begin, unsigned char const *end)
Flush all the generated code snippets of a vtable, on platforms that require it.
static unsigned char * addLocalFunctions(Slot **slots, unsigned char *code, sal_PtrDiff writetoexecdiff, typelib_InterfaceTypeDescription const *type, sal_Int32 functionOffset, sal_Int32 functionCount, sal_Int32 vtableOffset)
Fill the vtable slots corresponding to all local (i.e., not inherited) functions of a given interface...
void freeBlock(Block const &block) const
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
struct _typelib_TypeDescription typelib_TypeDescription
sal_Int32 getLocalFunctions(typelib_InterfaceTypeDescription const *type)
Calculate the number of local functions of an interface type.
sal_Int32 getPrimaryFunctions(typelib_InterfaceTypeDescription *type)
Calculate the number of primary functions of an interface type.
constexpr OUStringLiteral first
enumrange< T >::Iterator begin(enumrange< T >)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
sal_Size size
The size of the raw vtable block, in bytes.
void * exec
When separately mmapping the block for writing and executing exec points to the same memory as start,...
void * start
The start of the raw vtable block.
The vtable structure corresponding to an interface type.
std::unique_ptr< Block[]> blocks
An array of blocks, representing the multiple vtables of a (multiple-inheritance) type.
sal_Int32 count
The number of blocks/vtables.
sal_Bool SAL_CALL typelib_typedescription_complete(typelib_TypeDescription **ppTypeDescr) SAL_THROW_EXTERN_C()