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);
191 auto it =
m_map.find(name);
192 if (it ==
m_map.end()) {
193 for (sal_Int32
i = 0;
i < type->nBaseTypes; ++
i) {
194 offset = calculate(type->ppBaseTypes[
i], offset);
198 reinterpret_cast< typelib_TypeDescription ** >(&type));
204 VtableFactory::VtableFactory(): m_arena(
206 "bridges::cpp_uno::shared::VtableFactory",
208 0, nullptr, allocExec, freeExec, 0))
211 throw std::bad_alloc();
217 osl::MutexGuard guard(
m_mutex);
218 for (
const auto& rEntry :
m_map) {
219 for (sal_Int32 j = 0; j < rEntry.second.count; ++j) {
228 typelib_InterfaceTypeDescription * type)
230 OUString
name(type->aBase.pTypeName);
231 osl::MutexGuard guard(
m_mutex);
232 Map::iterator
i(
m_map.find(name));
238 vtables.
count =
static_cast< sal_Int32
>(blocks.size());
240 for (sal_Int32 j = 0; j < vtables.
count; ++j) {
241 vtables.
blocks[j] = blocks[j];
243 i =
m_map.emplace(name, std::move(vtables)).first;
249 #ifdef USE_DOUBLE_MMAP
253 std::size_t pagesize = sysconf(_SC_PAGESIZE);
254 block.size = (size + (pagesize - 1)) & ~(pagesize - 1);
258 block.start = block.exec = rtl_arena_alloc(
m_arena, &block.size);
259 if (block.start !=
nullptr) {
263 osl::Security aSecurity;
264 OUString strDirectory;
265 OUString strURLDirectory;
266 if (aSecurity.getHomeDir(strURLDirectory))
267 osl::File::getSystemPathFromFileURL(strURLDirectory, strDirectory);
269 for (
int i = strDirectory.isEmpty() ? 1 : 0;
i < 2; ++
i)
271 if (strDirectory.isEmpty())
272 strDirectory =
"/tmp";
274 strDirectory +=
"/.execoooXXXXXX";
276 std::unique_ptr<char[]> tmpfname(
new char[aTmpName.getLength()+1]);
277 strncpy(tmpfname.get(), aTmpName.getStr(), aTmpName.getLength()+1);
279 if ((block.fd = mkstemp(tmpfname.get())) == -1)
280 fprintf(stderr,
"mkstemp(\"%s\") failed: %s\n", tmpfname.get(), strerror(errno));
285 unlink(tmpfname.get());
287 #if defined(HAVE_POSIX_FALLOCATE)
288 int err = posix_fallocate(block.fd, 0, block.size);
290 int err = ftruncate(block.fd, block.size);
294 #if defined(HAVE_POSIX_FALLOCATE)
295 SAL_WARN(
"bridges",
"posix_fallocate failed with code " << err);
297 SAL_WARN(
"bridges",
"truncation of executable memory area failed with code " << err);
303 block.start = mmap(
nullptr, block.size, PROT_READ | PROT_WRITE, MAP_SHARED, block.fd, 0);
304 if (block.start== MAP_FAILED) {
305 block.start =
nullptr;
307 block.exec = mmap(
nullptr, block.size, PROT_READ | PROT_EXEC, MAP_SHARED, block.fd, 0);
308 if (block.exec == MAP_FAILED) {
309 block.exec =
nullptr;
313 if (block.start && block.exec && block.fd != -1)
318 strDirectory.clear();
320 return (block.start !=
nullptr && block.exec !=
nullptr);
325 if (block.fd == -1 && block.start == block.exec && block.start !=
nullptr)
326 rtl_arena_free(
m_arena, block.start, block.size);
329 if (block.start) munmap(block.start, block.size);
330 if (block.exec) munmap(block.exec, block.size);
331 if (block.fd != -1)
close(block.fd);
339 return block.
start !=
nullptr;
349 typelib_InterfaceTypeDescription * type, sal_Int32 vtableNumber,
350 typelib_InterfaceTypeDescription * mostDerived,
bool includePrimary)
const
353 #if defined MACOSX && defined __aarch64__
354 JitMemoryProtectionGuard guard;
356 if (includePrimary) {
361 throw std::bad_alloc();
365 block.
start, slotCount, vtableNumber, mostDerived);
366 unsigned char * codeBegin =
367 reinterpret_cast< unsigned char *
>(slots);
368 unsigned char *
code = codeBegin;
369 sal_Int32 vtableOffset = blocks.size() *
sizeof (
Slot *);
370 for (typelib_InterfaceTypeDescription
const * type2 = type;
371 type2 !=
nullptr; type2 = type2->pBaseTypeDescription)
376 reinterpret_cast<sal_uIntPtr>(block.
exec) - reinterpret_cast<sal_uIntPtr>(block.
start),
384 #ifdef USE_DOUBLE_MMAP
389 blocks.push_back(block);
396 for (sal_Int32
i = 0;
i < type->nBaseTypes; ++
i) {
398 blocks, baseOffset, type->ppBaseTypes[
i],
399 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 >)
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
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.