LCOV - code coverage report
Current view: top level - asmjit - virtmem.h (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 3 4 75.0 %
Date: 2026-11-05 10:19:06 Functions: 0 0 -

          Line data    Source code
       1             : #ifdef __PLUMED_HAS_ASMJIT
       2             : // This file is part of AsmJit project <https://asmjit.com>
       3             : //
       4             : // See asmjit.h or LICENSE.md for license and copyright information
       5             : // SPDX-License-Identifier: Zlib
       6             : 
       7             : #ifndef ASMJIT_CORE_VIRTMEM_H_INCLUDED
       8             : #define ASMJIT_CORE_VIRTMEM_H_INCLUDED
       9             : 
      10             : #include "api-config.h"
      11             : #ifndef ASMJIT_NO_JIT
      12             : 
      13             : #include "globals.h"
      14             : 
      15             : ASMJIT_BEGIN_NAMESPACE
      16             : 
      17             : //! \addtogroup asmjit_virtual_memory
      18             : //! \{
      19             : 
      20             : //! Virtual memory management.
      21             : namespace VirtMem {
      22             : 
      23             : //! Flushes instruction cache in the given region.
      24             : //!
      25             : //! Only useful on non-x86 architectures, however, it's a good practice to call it on any platform to make your
      26             : //! code more portable.
      27             : ASMJIT_API void flushInstructionCache(void* p, size_t size) noexcept;
      28             : 
      29             : //! Virtual memory information.
      30             : struct Info {
      31             :   //! Virtual memory page size.
      32             :   uint32_t pageSize;
      33             :   //! Virtual memory page granularity.
      34             :   uint32_t pageGranularity;
      35             : };
      36             : 
      37             : //! Returns virtual memory information, see `VirtMem::Info` for more details.
      38             : ASMJIT_API Info info() noexcept;
      39             : 
      40             : //! Virtual memory access and mmap-specific flags.
      41             : enum class MemoryFlags : uint32_t {
      42             :   //! No flags.
      43             :   kNone = 0,
      44             : 
      45             :   //! Memory is readable.
      46             :   kAccessRead = 0x00000001u,
      47             : 
      48             :   //! Memory is writable.
      49             :   kAccessWrite = 0x00000002u,
      50             : 
      51             :   //! Memory is executable.
      52             :   kAccessExecute = 0x00000004u,
      53             : 
      54             :   //! A combination of \ref MemoryFlags::kAccessRead and \ref MemoryFlags::kAccessWrite.
      55             :   kAccessReadWrite = kAccessRead | kAccessWrite,
      56             : 
      57             :   //! A combination of \ref MemoryFlags::kAccessRead, \ref MemoryFlags::kAccessWrite.
      58             :   kAccessRW = kAccessRead | kAccessWrite,
      59             : 
      60             :   //! A combination of \ref MemoryFlags::kAccessRead and \ref MemoryFlags::kAccessExecute.
      61             :   kAccessRX = kAccessRead | kAccessExecute,
      62             : 
      63             :   //! A combination of \ref MemoryFlags::kAccessRead, \ref MemoryFlags::kAccessWrite, and
      64             :   //! \ref MemoryFlags::kAccessExecute.
      65             :   kAccessRWX = kAccessRead | kAccessWrite | kAccessExecute,
      66             : 
      67             :   //! Use a `MAP_JIT` flag available on Apple platforms (introduced by Mojave), which allows JIT code to be executed
      68             :   //! in MAC bundles. This flag is not turned on by default, because when a process uses `fork()` the child process
      69             :   //! has no access to the pages mapped with `MAP_JIT`, which could break code that doesn't expect this behavior.
      70             :   //!
      71             :   //! \note This flag can only be used with \ref VirtMem::alloc().
      72             :   kMMapEnableMapJit = 0x00000010u,
      73             : 
      74             :   //! Pass `PROT_MAX(PROT_READ)` to mmap() on platforms that support `PROT_MAX`.
      75             :   //!
      76             :   //! \note This flag can only be used with \ref VirtMem::alloc().
      77             :   kMMapMaxAccessRead = 0x00000020u,
      78             :   //! Pass `PROT_MAX(PROT_WRITE)` to mmap() on platforms that support `PROT_MAX`.
      79             :   //!
      80             :   //! \note This flag can only be used with \ref VirtMem::alloc().
      81             :   kMMapMaxAccessWrite = 0x00000040u,
      82             :   //! Pass `PROT_MAX(PROT_EXEC)` to mmap() on platforms that support `PROT_MAX`.
      83             :   //!
      84             :   //! \note This flag can only be used with \ref VirtMem::alloc().
      85             :   kMMapMaxAccessExecute = 0x00000080u,
      86             : 
      87             :   //! A combination of \ref MemoryFlags::kMMapMaxAccessRead and \ref MemoryFlags::kMMapMaxAccessWrite.
      88             :   kMMapMaxAccessReadWrite = kMMapMaxAccessRead | kMMapMaxAccessWrite,
      89             : 
      90             :   //! A combination of \ref MemoryFlags::kMMapMaxAccessRead and \ref MemoryFlags::kMMapMaxAccessWrite.
      91             :   kMMapMaxAccessRW = kMMapMaxAccessRead | kMMapMaxAccessWrite,
      92             : 
      93             :   //! A combination of \ref MemoryFlags::kMMapMaxAccessRead and \ref MemoryFlags::kMMapMaxAccessExecute.
      94             :   kMMapMaxAccessRX = kMMapMaxAccessRead | kMMapMaxAccessExecute,
      95             : 
      96             :   //! A combination of \ref MemoryFlags::kMMapMaxAccessRead, \ref MemoryFlags::kMMapMaxAccessWrite, \ref
      97             :   //! MemoryFlags::kMMapMaxAccessExecute.
      98             :   kMMapMaxAccessRWX = kMMapMaxAccessRead | kMMapMaxAccessWrite | kMMapMaxAccessExecute,
      99             : 
     100             :   //! Not an access flag, only used by `allocDualMapping()` to override the default allocation strategy to always use
     101             :   //! a 'tmp' directory instead of "/dev/shm" (on POSIX platforms). Please note that this flag will be ignored if the
     102             :   //! operating system allows to allocate an executable memory by a different API than `open()` or `shm_open()`. For
     103             :   //! example on Linux `memfd_create()` is preferred and on BSDs `shm_open(SHM_ANON, ...)` is used if SHM_ANON is
     104             :   //! defined.
     105             :   //!
     106             :   //! \note This flag can only be used with \ref VirtMem::alloc().
     107             :   kMappingPreferTmp = 0x80000000u
     108             : };
     109           0 : ASMJIT_DEFINE_ENUM_FLAGS(MemoryFlags)
     110             : 
     111             : //! Allocates virtual memory by either using `mmap()` (POSIX) or `VirtualAlloc()` (Windows).
     112             : //!
     113             : //! \note `size` should be aligned to page size, use \ref VirtMem::info() to obtain it. Invalid size will not be
     114             : //! corrected by the implementation and the allocation would not succeed in such case.
     115             : ASMJIT_API Error alloc(void** p, size_t size, MemoryFlags flags) noexcept;
     116             : 
     117             : //! Releases virtual memory previously allocated by \ref VirtMem::alloc().
     118             : //!
     119             : //! \note The size must be the same as used by \ref VirtMem::alloc(). If the size is not the same value the call
     120             : //! will fail on any POSIX system, but pass on Windows, because it's implemented differently.
     121             : ASMJIT_API Error release(void* p, size_t size) noexcept;
     122             : 
     123             : //! A cross-platform wrapper around `mprotect()` (POSIX) and `VirtualProtect()` (Windows).
     124             : ASMJIT_API Error protect(void* p, size_t size, MemoryFlags flags) noexcept;
     125             : 
     126             : //! Dual memory mapping used to map an anonymous memory into two memory regions where one region is read-only, but
     127             : //! executable, and the second region is read+write, but not executable. See \ref VirtMem::allocDualMapping() for
     128             : //! more details.
     129             : struct DualMapping {
     130             :   //! Pointer to data with 'Read+Execute' access (this memory is not writable).
     131             :   void* rx;
     132             :   //! Pointer to data with 'Read+Write' access (this memory is not executable).
     133             :   void* rw;
     134             : };
     135             : 
     136             : //! Allocates virtual memory and creates two views of it where the first view has no write access. This is an addition
     137             : //! to the API that should be used in cases in which the operating system either enforces W^X security policy or the
     138             : //! application wants to use this policy by default to improve security and prevent an accidental (or purposed)
     139             : //! self-modifying code.
     140             : //!
     141             : //! The memory returned in the `dm` are two independent mappings of the same shared memory region. You must use
     142             : //! \ref VirtMem::releaseDualMapping() to release it when it's no longer needed. Never use `VirtMem::release()` to
     143             : //! release the memory returned by `allocDualMapping()` as that would fail on Windows.
     144             : //!
     145             : //! \remarks Both pointers in `dm` would be set to `nullptr` if the function fails.
     146             : ASMJIT_API Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags flags) noexcept;
     147             : 
     148             : //! Releases virtual memory mapping previously allocated by \ref VirtMem::allocDualMapping().
     149             : //!
     150             : //! \remarks Both pointers in `dm` would be set to `nullptr` if the function succeeds.
     151             : ASMJIT_API Error releaseDualMapping(DualMapping* dm, size_t size) noexcept;
     152             : 
     153             : //! Hardened runtime flags.
     154             : enum class HardenedRuntimeFlags : uint32_t {
     155             :   //! No flags.
     156             :   kNone = 0,
     157             : 
     158             :   //! Hardened runtime is enabled - it's not possible to have "Write & Execute" memory protection. The runtime
     159             :   //! enforces W^X (either write or execute).
     160             :   //!
     161             :   //! \note If the runtime is hardened it means that an operating system specific protection is used. For example on
     162             :   //! MacOS platform it's possible to allocate memory with MAP_JIT flag and then use `pthread_jit_write_protect_np()`
     163             :   //! to temporarily swap access permissions for the current thread. Dual mapping is also a possibility on X86/X64
     164             :   //! architecture.
     165             :   kEnabled = 0x00000001u,
     166             : 
     167             :   //! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific).
     168             :   kMapJit = 0x00000002u
     169             : };
     170             : ASMJIT_DEFINE_ENUM_FLAGS(HardenedRuntimeFlags)
     171             : 
     172             : //! Hardened runtime information.
     173             : struct HardenedRuntimeInfo {
     174             :   //! Hardened runtime flags.
     175             :   HardenedRuntimeFlags flags;
     176             : };
     177             : 
     178             : //! Returns runtime features provided by the OS.
     179             : ASMJIT_API HardenedRuntimeInfo hardenedRuntimeInfo() noexcept;
     180             : 
     181             : //! Values that can be used with `protectJitMemory()` function.
     182             : enum class ProtectJitAccess : uint32_t {
     183             :   //! Protect JIT memory with Read+Write permissions.
     184             :   kReadWrite = 0,
     185             :   //! Protect JIT memory with Read+Execute permissions.
     186             :   kReadExecute = 1
     187             : };
     188             : 
     189             : //! Protects access of memory mapped with MAP_JIT flag for the current thread.
     190             : //!
     191             : //! \note This feature is only available on Apple hardware (AArch64) at the moment and and uses a non-portable
     192             : //! `pthread_jit_write_protect_np()` call when available.
     193             : //!
     194             : //! This function must be called before and after a memory mapped with MAP_JIT flag is modified. Example:
     195             : //!
     196             : //! ```
     197             : //! void* codePtr = ...;
     198             : //! size_t codeSize = ...;
     199             : //!
     200             : //! VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite);
     201             : //! memcpy(codePtr, source, codeSize);
     202             : //! VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute);
     203             : //! VirtMem::flushInstructionCache(codePtr, codeSize);
     204             : //! ```
     205             : //!
     206             : //! See \ref ProtectJitReadWriteScope, which makes it simpler than the code above.
     207             : ASMJIT_API void protectJitMemory(ProtectJitAccess access) noexcept;
     208             : 
     209             : //! JIT protection scope that prepares the given memory block to be written to in the current thread.
     210             : //!
     211             : //! It calls `VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite)` at construction time and
     212             : //! `VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute)` combined with `flushInstructionCache()`
     213             : //! in destructor. The purpose of this class is to make writing to JIT memory easier.
     214             : class ProtectJitReadWriteScope {
     215             : public:
     216             :   void* _rxPtr;
     217             :   size_t _size;
     218             : 
     219             :   //! Makes the given memory block RW protected.
     220             :   ASMJIT_FORCE_INLINE ProtectJitReadWriteScope(void* rxPtr, size_t size) noexcept
     221             :     : _rxPtr(rxPtr),
     222             :       _size(size) {
     223       27492 :     protectJitMemory(ProtectJitAccess::kReadWrite);
     224             :   }
     225             : 
     226             :   // Not copyable.
     227             :   ProtectJitReadWriteScope(const ProtectJitReadWriteScope& other) = delete;
     228             : 
     229             :   //! Makes the memory block RX protected again and flushes instruction cache.
     230             :   ASMJIT_FORCE_INLINE  ~ProtectJitReadWriteScope() noexcept {
     231       27492 :     protectJitMemory(ProtectJitAccess::kReadExecute);
     232       27492 :     flushInstructionCache(_rxPtr, _size);
     233             :   }
     234             : };
     235             : 
     236             : } // VirtMem
     237             : 
     238             : //! \}
     239             : 
     240             : ASMJIT_END_NAMESPACE
     241             : 
     242             : #endif
     243             : #endif // ASMJIT_CORE_VIRTMEM_H_INCLUDED
     244             : 
     245             : #endif // __PLUMED_HAS_ASMJIT

Generated by: LCOV version 1.16