25 #include <osl/thread.h>
26 #include <osl/security.hxx>
27 #include <osl/file.hxx>
28 #include <osl/mutex.hxx>
29 #include <rtl/alloc.h>
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__
64 extern "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
70 pagesize = getpagesize();
72 pagesize = sysconf(_SC_PAGESIZE);
77 pagesize = info.dwPageSize;
79 #error Unsupported platform
81 std::size_t
n = (*size + (pagesize - 1)) & ~(pagesize - 1);
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);
126 extern "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__
138 struct JitMemoryProtectionGuard {
139 JitMemoryProtectionGuard() { pthread_jit_write_protect_np(0); }
140 ~JitMemoryProtectionGuard() { pthread_jit_write_protect_np(1); }
147 public std::vector<Block>
178 {
return m_map.find(name)->second; }
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);
197 reinterpret_cast< typelib_TypeDescription ** >(&type));
203 VtableFactory::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);
231 Map::iterator
i(
m_map.find(name));
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];
242 i =
m_map.emplace(name, std::move(vtables)).first;
248 #ifdef USE_DOUBLE_MMAP
252 std::size_t pagesize = sysconf(_SC_PAGESIZE);
253 block.size = (size + (pagesize - 1)) & ~(pagesize - 1);
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);
sal_Int32 createVtables(GuardedBlocks &blocks, BaseOffset const &baseOffset, typelib_InterfaceTypeDescription *type, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *mostDerived, bool includePrimary) const
sal_Int32 getPrimaryFunctions(typelib_InterfaceTypeDescription *type)
Calculate the number of primary functions of an interface type.
std::unique_ptr< Block[]> blocks
An array of blocks, representing the multiple vtables of a (multiple-inheritance) type...
std::unordered_map< OUString, sal_Int32 > m_map
VtableFactory const & m_factory
sal_Int32 calculate(typelib_InterfaceTypeDescription *type, sal_Int32 offset)
Hand out vtable structures for interface type descriptions.
static std::size_t getBlockSize(sal_Int32 slotCount)
Calculate the size of a raw vtable block.
enumrange< T >::Iterator begin(enumrange< T >)
sal_Bool SAL_CALL typelib_typedescription_complete(typelib_TypeDescription **ppTypeDescr) SAL_THROW_EXTERN_C()
static Slot * initializeBlock(void *block, sal_Int32 slotCount, sal_Int32 vtableNumber, typelib_InterfaceTypeDescription *type)
Initialize a raw vtable block.
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
GuardedBlocks(const GuardedBlocks &)=delete
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...
sal_Int32 getFunctionOffset(OUString const &name) const
The vtable structure corresponding to an interface type.
void * start
The start of the raw vtable block.
sal_Int32 getLocalFunctions(typelib_InterfaceTypeDescription const *type)
Calculate the number of local functions of an interface type.
bool createBlock(Block &block, sal_Int32 slotCount) const
enumrange< T >::Iterator end(enumrange< T >)
sal_Size size
The size of the raw vtable block, in bytes.
GuardedBlocks(VtableFactory const &factory)
void * exec
When separately mmapping the block for writing and executing exec points to the same memory as start...
const GuardedBlocks & operator=(const GuardedBlocks &)=delete
#define SAL_INFO(area, stream)
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.
sal_Int32 count
The number of blocks/vtables.
#define SAL_WARN(area, stream)
void freeBlock(Block const &block) const
BaseOffset(typelib_InterfaceTypeDescription *type)
const Vtables & getVtables(typelib_InterfaceTypeDescription *type)
Given an interface type description, return its corresponding vtable structure.