diff --git a/.travis.yml b/.travis.yml index b8f0aaf..2a05d4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,160 +8,51 @@ env: - BUILD_TOOLCHAIN="Unix Makefiles" - MAKEFLAGS="-j2" -dist: xenial +dist: bionic matrix: include: - - name: "Linux GCC 4.8 [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.8 && CXX=g++-4.8" CXXFLAGS=-m32 LDFLAGS=-m32 + - name: "Linux Clang Default [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=clang-9 && CXX=clang++-9" os: linux addons: apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-4.8, g++-4.8-multilib, "linux-libc-dev:i386"] + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [clang++-9] - - name: "Linux GCC 4.8 [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.8 && CXX=g++-4.8" + - name: "Linux Clang Default [64-bit] [REL]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" os: linux addons: apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-4.8] + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [clang++-9] - - name: "Linux GCC 4.9 [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.9 && CXX=g++-4.9" CXXFLAGS=-m32 LDFLAGS=-m32 + - name: "Linux Clang Default [64-bit] [REL] [Sanitize=Address]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" SANITIZE=address os: linux addons: apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-4.9, g++-4.9-multilib, "linux-libc-dev:i386"] + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [clang++-9] - - name: "Linux GCC 4.9 [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.9 && CXX=g++-4.9" + - name: "Linux Clang Default [64-bit] [REL] [Sanitize=Undefined]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" SANITIZE=undefined os: linux addons: apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-4.9] - - - name: "Linux GCC 5.X [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-5 && CXX=g++-5" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-5, g++-5-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 5.X [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-5 && CXX=g++-5" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-5] - - - name: "Linux GCC 6.X [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-6 && CXX=g++-6" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-6, g++-6-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 6.X [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-6 && CXX=g++-6" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-6] - - - name: "Linux GCC 7.X [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-7 && CXX=g++-7" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-7, g++-7-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 7.X [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-7 && CXX=g++-7" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-7] - - - name: "Linux GCC 8.X [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-8 && CXX=g++-8" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-8, g++-8-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 8.X [32-bit] [REL]" - env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-8 && CXX=g++-8" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-8, g++-8-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 8.X [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-8 && CXX=g++-8" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-8] - - - name: "Linux GCC 8.X [64-bit] [REL]" - env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-8 && CXX=g++-8" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-8] - - - name: "Linux GCC 9.X [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-9 && CXX=g++-9" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-9, g++-9-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 9.X [32-bit] [REL]" - env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-9 && CXX=g++-9" CXXFLAGS=-m32 LDFLAGS=-m32 - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-9, g++-9-multilib, "linux-libc-dev:i386"] - - - name: "Linux GCC 9.X [64-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-9 && CXX=g++-9" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-9] - - - name: "Linux GCC 9.X [64-bit] [REL]" - env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-9 && CXX=g++-9" - os: linux - addons: - apt: - sources: [ubuntu-toolchain-r-test] - packages: [g++-9] + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [clang++-9] - name: "Linux GCC Default [64-bit] [DBG + Valgrind]" env: BUILD_MATRIX="BUILD_TYPE=Debug" USE_VALGRIND=1 os: linux addons: apt: - sources: [ubuntu-toolchain-r-test] packages: [valgrind] - name: "Linux GCC Default [64-bit] [REL + Valgrind]" @@ -169,16 +60,135 @@ matrix: os: linux addons: apt: - sources: [ubuntu-toolchain-r-test] packages: [valgrind] + - name: "Linux GCC 4.8 [32-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.8 && CXX=g++-4.8" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + packages: [g++-4.8, g++-4.8-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 4.8 [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.8 && CXX=g++-4.8" + os: linux + addons: + apt: + packages: [g++-4.8] + + - name: "Linux GCC 5.X [32-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-5 && CXX=g++-5" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + packages: [g++-5, g++-5-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 5.X [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-5 && CXX=g++-5" + os: linux + addons: + apt: + packages: [g++-5] + + - name: "Linux GCC 6.X [32-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-6 && CXX=g++-6" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + packages: [g++-6, g++-6-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 6.X [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-6 && CXX=g++-6" + os: linux + addons: + apt: + packages: [g++-6] + + - name: "Linux GCC 7.X [32-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-7 && CXX=g++-7" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + packages: [g++-7, g++-7-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 7.X [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-7 && CXX=g++-7" + os: linux + addons: + apt: + packages: [g++-7] + + - name: "Linux GCC 8.X [32-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-8 && CXX=g++-8" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + packages: [g++-8, g++-8-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 8.X [32-bit] [REL]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-8 && CXX=g++-8" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + packages: [g++-8, g++-8-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 8.X [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-8 && CXX=g++-8" + os: linux + addons: + apt: + packages: [g++-8] + + - name: "Linux GCC 8.X [64-bit] [REL]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-8 && CXX=g++-8" + os: linux + addons: + apt: + packages: [g++-8] + + - name: "Linux GCC 9.X [32-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-9 && CXX=g++-9" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [g++-9, g++-9-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 9.X [32-bit] [REL]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-9 && CXX=g++-9" CXXFLAGS=-m32 LDFLAGS=-m32 + os: linux + addons: + apt: + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [g++-9, g++-9-multilib, "linux-libc-dev:i386"] + + - name: "Linux GCC 9.X [64-bit] [DBG]" + env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-9 && CXX=g++-9" + os: linux + addons: + apt: + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [g++-9] + + - name: "Linux GCC 9.X [64-bit] [REL]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=gcc-9 && CXX=g++-9" + os: linux + addons: + apt: + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [g++-9] + - name: "OSX Clang XCode 9.4 [32-bit] [DBG]" - env: BUILD_MATRIX="BUILD_TYPE=Debug" CXXFLAGS=-m32 && LDFLAGS=-m32 + env: BUILD_MATRIX="BUILD_TYPE=Debug" CXXFLAGS=-m32 LDFLAGS=-m32 os: osx osx_image: xcode9.4 - name: "OSX Clang XCode 9.4 [32-bit] [REL]" - env: BUILD_MATRIX="BUILD_TYPE=Release" CXXFLAGS=-m32 && LDFLAGS=-m32 + env: BUILD_MATRIX="BUILD_TYPE=Release" CXXFLAGS=-m32 LDFLAGS=-m32 os: osx osx_image: xcode9.4 @@ -236,9 +246,9 @@ before_script: - cd build - | if [[ "$BUILD_TOOLCHAIN" =~ ^Visual\ Studio ]]; then - cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 + cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 -DASMJIT_SANITIZE="${SANITIZE}" else - cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 -DCMAKE_PREFIX_PATH="$MINGW_PATH" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" + cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 -DASMJIT_SANITIZE="${SANITIZE}" -DCMAKE_PREFIX_PATH="${MINGW_PATH}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" fi - cd .. @@ -246,7 +256,7 @@ script: - cd build - | if [[ "$BUILD_TOOLCHAIN" =~ ^Visual\ Studio ]]; then - cmake --build . --config ${BUILD_TYPE} -- -nologo -v:quiet + cmake --build . --config ${BUILD_TYPE} -- -nologo -v:minimal cd ${BUILD_TYPE} else cmake --build . diff --git a/CMakeLists.txt b/CMakeLists.txt index 407fb41..b6082ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,20 @@ set(ASMJIT_SANITIZE ${ASMJIT_SANITIZE} CACHE BOOL "Build with C/C++ s set(ASMJIT_BUILD_X86 ${ASMJIT_BUILD_X86} CACHE BOOL "Build X86 backends (X86 and X86_64)") set(ASMJIT_BUILD_ARM ${ASMJIT_BUILD_ARM} CACHE BOOL "Build ARM backends") +# ============================================================================= +# [AsmJit - Project] +# ============================================================================= + +set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir. +set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker. +set(ASMJIT_LIBS "") # Dependencies of libs/apps that want to use AsmJit. +set(ASMJIT_CFLAGS "") # Public compiler flags. +set(ASMJIT_PRIVATE_CFLAGS "") # Private compiler flags independent of build type. +set(ASMJIT_PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds. +set(ASMJIT_PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds. +set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers. +set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers. + # ============================================================================= # [AsmJit - Utilities] # ============================================================================= @@ -79,6 +93,30 @@ function(asmjit_detect_cflags out) set(${out} "${out_array}" PARENT_SCOPE) endfunction() +# Support for various sanitizers provided by C/C++ compilers. +function(asmjit_detect_sanitizers out) + set(_out_array ${${out}}) + set(_flags "") + + foreach(_arg ${ARGN}) + string(REPLACE "," ";" _arg "${_arg}") + list(APPEND _flags ${_arg}) + endforeach() + + foreach(_flag ${_flags}) + if (NOT "${_flag}" MATCHES "^-fsanitize=") + SET(_flag "-fsanitize=${_flag}") + endif() + + # Sanitizers also require link flags, see CMAKE_REQUIRED_FLAGS. + set(CMAKE_REQUIRED_FLAGS "${_flag}") + asmjit_detect_cflags(_out_array ${_flag}) + unset(CMAKE_REQUIRED_FLAGS) + endforeach() + + set(${out} "${_out_array}" PARENT_SCOPE) +endfunction() + function(asmjit_add_target target target_type src deps cflags cflags_dbg cflags_rel) if ("${target_type}" STREQUAL "EXECUTABLE") add_executable(${target} ${src}) @@ -89,8 +127,8 @@ function(asmjit_add_target target target_type src deps cflags cflags_dbg cflags_ target_link_libraries(${target} PRIVATE ${deps}) # target_link_options was added in cmake 3.13, which doesn't work for us. - # target_link_options(${target} PRIVATE ${ASMJIT_SANITIZE_FLAGS}) - foreach(link_flag ${ASMJIT_SANITIZE_FLAGS}) + # target_link_options(${target} PRIVATE ${flags}) + foreach(link_flag ${ASMJIT_SANITIZE_LFLAGS}) set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${link_flag}") endforeach() @@ -101,11 +139,11 @@ function(asmjit_add_target target target_type src deps cflags cflags_dbg cflags_ endif() set_property(TARGET ${target} PROPERTY CXX_EXTENSIONS NO) set_property(TARGET ${target} PROPERTY CXX_VISIBILITY_PRESET hidden) - target_compile_options(${target} PRIVATE ${cflags} ${ASMJIT_SANITIZE_FLAGS} $<$:${cflags_dbg}> $<$>:${cflags_rel}>) + target_compile_options(${target} PRIVATE ${cflags} ${ASMJIT_SANITIZE_CFLAGS} $<$:${cflags_dbg}> $<$>:${cflags_rel}>) endfunction() # ============================================================================= -# [AsmJit - Project] +# [AsmJit - Compiler Support] # ============================================================================= set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir. @@ -115,7 +153,8 @@ set(ASMJIT_CFLAGS "") # Public compiler flags. set(ASMJIT_PRIVATE_CFLAGS "") # Private compiler flags independent of build type. set(ASMJIT_PRIVATE_CFLAGS_DBG "") # Private compiler flags used by debug builds. set(ASMJIT_PRIVATE_CFLAGS_REL "") # Private compiler flags used by release builds. -set(ASMJIT_SANITIZE_FLAGS "") # Sanitizer flags used as compile and link flags. +set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers. +set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers. # TODO: Backward compatibility. set(ASMJIT_INCLUDE_DIR "${ASMJIT_INCLUDE_DIRS}") @@ -146,8 +185,25 @@ if (NOT ASMJIT_NO_CUSTOM_FLAGS) endif() endif() -if (ASMJIT_SANITIZE AND "${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang|AppleClang)$") - asmjit_detect_cflags(ASMJIT_SANITIZE_FLAGS "-fsanitize=undefined") +# Support for sanitizers. +if (ASMJIT_SANITIZE) + ASMJIT_detect_sanitizers(ASMJIT_SANITIZE_CFLAGS ${ASMJIT_SANITIZE}) + if (ASMJIT_SANITIZE_CFLAGS) + message("-- Enabling sanitizers: '${ASMJIT_SANITIZE_CFLAGS}'") + + # Linker must receive the same flags as the compiler when it comes to sanitizers. + set(ASMJIT_SANITIZE_LFLAGS ${ASMJIT_SANITIZE_CFLAGS}) + + # Don't omit frame pointer if sanitizers are enabled. + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") + list(APPEND ASMJIT_SANITIZE_CFLAGS -Oy-) + else() + list(APPEND ASMJIT_SANITIZE_CFLAGS -fno-omit-frame-pointer -g) + endif() + + list(APPEND ASMJIT_PRIVATE_CFLAGS ${ASMJIT_SANITIZE_CFLAGS}) + list(APPEND ASMJIT_PRIVATE_LFLAGS ${ASMJIT_SANITIZE_LFLAGS}) + endif() endif() if (NOT WIN32) diff --git a/src/asmjit/core/virtmem.cpp b/src/asmjit/core/virtmem.cpp index f785a8a..c19799f 100644 --- a/src/asmjit/core/virtmem.cpp +++ b/src/asmjit/core/virtmem.cpp @@ -27,6 +27,18 @@ #include #endif + // Apple recently introduced MAP_JIT flag, which we want to use. + #if defined(__APPLE__) + #include + #if TARGET_OS_OSX + #include + #endif + // Older SDK doesn't define `MAP_JIT`. + #ifndef MAP_JIT + #define MAP_JIT 0x800 + #endif + #endif + // BSD/OSX: `MAP_ANONYMOUS` is not defined, `MAP_ANON` is. #if !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON @@ -35,13 +47,19 @@ #include +#if defined(__APPLE__) + #define ASMJIT_VM_SHM_DETECT 0 +#else + #define ASMJIT_VM_SHM_DETECT 1 +#endif + ASMJIT_BEGIN_NAMESPACE // ============================================================================ // [asmjit::VirtMem - Utilities] // ============================================================================ -static const uint32_t dualMappingFilter[2] = { +static const uint32_t VirtMem_dualMappingFilter[2] = { VirtMem::kAccessWrite, VirtMem::kAccessExecute }; @@ -51,7 +69,6 @@ static const uint32_t dualMappingFilter[2] = { // ============================================================================ #if defined(_WIN32) - struct ScopedHandle { inline ScopedHandle() noexcept : value(nullptr) {} @@ -148,7 +165,7 @@ Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) no void* ptr[2]; for (uint32_t i = 0; i < 2; i++) { - DWORD desiredAccess = VirtMem_accessToWinDesiredAccess(flags & ~dualMappingFilter[i]); + DWORD desiredAccess = VirtMem_accessToWinDesiredAccess(flags & ~VirtMem_dualMappingFilter[i]); ptr[i] = ::MapViewOfFile(handle.value, desiredAccess, 0, 0, size); if (ptr[i] == nullptr) { @@ -180,7 +197,6 @@ Error VirtMem::releaseDualMapping(DualMapping* dm, size_t size) noexcept { dm->rw = nullptr; return kErrorOk; } - #endif // ============================================================================ @@ -200,11 +216,12 @@ struct ScopedFD { int value; }; -#if defined(SYS_memfd_create) -// Zero initialized, if ever changed to '1' that would mean the syscall is not -// available and we must use `shm_open()` and `shm_unlink()`. -static volatile uint32_t vm_memfd_create_not_supported; -#endif +static void VirtMem_getInfo(VirtMem::Info& vmInfo) noexcept { + uint32_t pageSize = uint32_t(::getpagesize()); + + vmInfo.pageSize = pageSize; + vmInfo.pageGranularity = Support::max(pageSize, 65536); +} // Some operating systems don't allow /dev/shm to be executable. On Linux this // happens when /dev/shm is mounted with 'noexec', which is enforced by systemd. @@ -218,25 +235,6 @@ enum ShmStrategy : uint32_t { kShmStrategyTmpDir = 2 }; -#if defined(__APPLE__) - #define ASMJIT_VM_SHM_DETECT 0 -#else - #define ASMJIT_VM_SHM_DETECT 1 -#endif - -#if ASMJIT_VM_SHM_DETECT -// Initially don't assume anything. It has to be tested whether '/dev/shm' was -// mounted with 'noexec' flag or not. -static volatile uint32_t vm_shm_strategy = kShmStrategyUnknown; -#endif - -static void VirtMem_getInfo(VirtMem::Info& vmInfo) noexcept { - uint32_t pageSize = uint32_t(::getpagesize()); - - vmInfo.pageSize = pageSize; - vmInfo.pageGranularity = Support::max(pageSize, 65536); -} - // Posix specific implementation that uses `mmap()` and `munmap()`. static int VirtMem_accessToPosixProtection(uint32_t flags) noexcept { int protection = 0; @@ -246,6 +244,7 @@ static int VirtMem_accessToPosixProtection(uint32_t flags) noexcept { return protection; } +// Translates libc errors specific to VirtualMemory mapping to `asmjit::Error`. static Error VirtMem_makeErrorFromErrno(int e) noexcept { switch (e) { case EACCES: @@ -268,6 +267,75 @@ static Error VirtMem_makeErrorFromErrno(int e) noexcept { } } +#if defined(__APPLE__) +// Detects whether the current process is hardened, which means that pages that +// have WRITE and EXECUTABLE flags cannot be allocated without MAP_JIT flag. +static ASMJIT_INLINE bool VirtMem_isHardened() noexcept { + static volatile uint32_t globalHardenedFlag; + + enum HardenedFlag : uint32_t { + kHardenedFlagUnknown = 0, + kHardenedFlagDisabled = 1, + kHardenedFlagEnabled = 2 + }; + + uint32_t flag = globalHardenedFlag; + if (flag == kHardenedFlagUnknown) { + VirtMem::Info memInfo; + VirtMem_getInfo(memInfo); + + void* ptr = mmap(nullptr, memInfo.pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr == MAP_FAILED) { + flag = kHardenedFlagEnabled; + } + else { + flag = kHardenedFlagDisabled; + munmap(ptr, memInfo.pageSize); + } + globalHardenedFlag = flag; + } + + return flag == kHardenedFlagEnabled; +} + +// MAP_JIT flag required to run unsigned JIT code is only supported by kernel +// version 10.14+ (Mojave) and IOS. +static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept { +#if TARGET_OS_OSX + static volatile uint32_t globalVersion; + + uint32_t ver = globalVersion; + if (!ver) { + struct utsname osname; + uname(&osname); + ver = atoi(osname.release); + globalVersion = ver; + } + return ver >= 18; +#else + // Assume it's available. + return true; +#endif +} + +static ASMJIT_INLINE uint32_t VirtMem_appleSpecificMMapFlags(uint32_t flags) { + // Always use MAP_JIT flag if user asked for it (could be used for testing + // on non-hardened processes) and detect whether it must be used when the + // process is actually hardened (in that case it doesn't make sense to rely + // on user `flags`). + bool useMapJit = ((flags & VirtMem::kMMapEnableMapJit) != 0) || VirtMem_isHardened(); + if (useMapJit) + return VirtMem_hasMapJitSupport() ? MAP_JIT : 0u; + else + return 0; +} +#else +static ASMJIT_INLINE uint32_t VirtMem_appleSpecificMMapFlags(uint32_t flags) { + ASMJIT_UNUSED(flags); + return 0; +} +#endif + static const char* VirtMem_getTmpDir() noexcept { const char* tmpDir = getenv("TMPDIR"); return tmpDir ? tmpDir : "/tmp"; @@ -277,14 +345,19 @@ static Error VirtMem_openAnonymousMemory(int* fd, bool preferTmpOverDevShm) noex #if defined(SYS_memfd_create) // Linux specific 'memfd_create' - if the syscall returns `ENOSYS` it means // it's not available and we will never call it again (would be pointless). - if (!vm_memfd_create_not_supported) { + + // Zero initialized, if ever changed to '1' that would mean the syscall is not + // available and we must use `shm_open()` and `shm_unlink()`. + static volatile uint32_t memfd_create_not_supported; + + if (!memfd_create_not_supported) { *fd = (int)syscall(SYS_memfd_create, "vmem", 0); if (ASMJIT_LIKELY(*fd >= 0)) return kErrorOk; int e = errno; if (e == ENOSYS) - vm_memfd_create_not_supported = 1; + memfd_create_not_supported = 1; else return DebugUtils::errored(VirtMem_makeErrorFromErrno(e)); } @@ -373,11 +446,14 @@ static Error VirtMem_detectShmStrategy(uint32_t* strategyOut) noexcept { #if ASMJIT_VM_SHM_DETECT static Error VirtMem_getShmStrategy(uint32_t* strategyOut) noexcept { - uint32_t strategy = vm_shm_strategy; + // Initially don't assume anything. It has to be tested whether + // '/dev/shm' was mounted with 'noexec' flag or not. + static volatile uint32_t globalShmStrategy = kShmStrategyUnknown; + uint32_t strategy = globalShmStrategy; if (strategy == kShmStrategyUnknown) { ASMJIT_PROPAGATE(VirtMem_detectShmStrategy(&strategy)); - vm_shm_strategy = strategy; + globalShmStrategy = strategy; } *strategyOut = strategy; @@ -397,7 +473,8 @@ Error VirtMem::alloc(void** p, size_t size, uint32_t flags) noexcept { return DebugUtils::errored(kErrorInvalidArgument); int protection = VirtMem_accessToPosixProtection(flags); - void* ptr = mmap(nullptr, size, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + int mmFlags = MAP_PRIVATE | MAP_ANONYMOUS | VirtMem_appleSpecificMMapFlags(flags); + void* ptr = mmap(nullptr, size, protection, mmFlags, -1, 0); if (ptr == MAP_FAILED) return DebugUtils::errored(kErrorOutOfMemory); @@ -444,7 +521,7 @@ Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) no void* ptr[2]; for (uint32_t i = 0; i < 2; i++) { - ptr[i] = mmap(nullptr, size, VirtMem_accessToPosixProtection(flags & ~dualMappingFilter[i]), MAP_SHARED, fd.value, 0); + ptr[i] = mmap(nullptr, size, VirtMem_accessToPosixProtection(flags & ~VirtMem_dualMappingFilter[i]), MAP_SHARED, fd.value, 0); if (ptr[i] == MAP_FAILED) { // Get the error now before `munmap` has a chance to clobber it. int e = errno; diff --git a/src/asmjit/core/virtmem.h b/src/asmjit/core/virtmem.h index 3322452..8ff2427 100644 --- a/src/asmjit/core/virtmem.h +++ b/src/asmjit/core/virtmem.h @@ -38,9 +38,16 @@ enum Flags : uint32_t { //! A combination of `kAccessRead | kAccessWrite` kAccessReadWrite = 0x00000003u, + //! Use a `MAP_JIT` flag available on Apple platforms (OSX Mojave+), which + //! allows JIT code to be executed in OSX bundles. This flag is not turned + //! on by default, because when a process uses `fork()` the child process + //! has no access to the pages mapped with `MAP_JIT`, which could break code + //! that doesn't expect this behavior. + kMMapEnableMapJit = 0x00000010u, + //! Not an access flag, only used by `allocDualMapping()` to override the - //! default allocation strategy to always use a temporary directory instead - //! on "/dev/shm" (on POSIX systems). Please note that this flag will be + //! default allocation strategy to always use a 'tmp' directory instead of + //! "/dev/shm" (on POSIX platforms). Please note that this flag will be //! ignored if the operating system allows to allocate an executable memory //! by a different API than `open()` or `shm_open()`. For example on Linux //! `memfd_create()` is preferred and on BSDs `shm_open(SHM_ANON, ...)` is diff --git a/src/asmjit/x86/x86logging.cpp b/src/asmjit/x86/x86logging.cpp index c59c17a..80ae853 100644 --- a/src/asmjit/x86/x86logging.cpp +++ b/src/asmjit/x86/x86logging.cpp @@ -674,8 +674,6 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( // Format instruction options and instruction mnemonic. if (instId < Inst::_kIdCount) { - const InstDB::InstInfo& instInfo = InstDB::infoById(instId); - // SHORT|LONG options. if (options & Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.appendString("short ")); if (options & Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.appendString("long ")); diff --git a/tools/configure-sanitizers.sh b/tools/configure-sanitizers.sh new file mode 100755 index 0000000..46e332c --- /dev/null +++ b/tools/configure-sanitizers.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +CURRENT_DIR=`pwd` +BUILD_DIR="build" +BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1" + +echo "** Configuring '${BUILD_DIR}_rel_asan' [Sanitize=Address] **" +mkdir -p ../${BUILD_DIR}_rel_asan +cd ../${BUILD_DIR}_rel_asan +eval cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS} -DASMJIT_SANITIZE=address +cd ${CURRENT_DIR} + +echo "** Configuring '${BUILD_DIR}_rel_ubsan' [Sanitize=Undefined] **" +mkdir -p ../${BUILD_DIR}_rel_ubsan +cd ../${BUILD_DIR}_rel_ubsan +eval cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS} -DASMJIT_SANITIZE=undefined +cd ${CURRENT_DIR}