diff --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt --- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt +++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt @@ -73,6 +73,7 @@ memtag.h mem_map.h mem_map_base.h + mem_map_linux.h mutex.h options.h platform.h @@ -106,6 +107,7 @@ fuchsia.cpp linux.cpp mem_map.cpp + mem_map_linux.cpp release.cpp report.cpp rss_limit_checker.cpp diff --git a/compiler-rt/lib/scudo/standalone/mem_map.h b/compiler-rt/lib/scudo/standalone/mem_map.h --- a/compiler-rt/lib/scudo/standalone/mem_map.h +++ b/compiler-rt/lib/scudo/standalone/mem_map.h @@ -20,6 +20,8 @@ #include "linux.h" #include "trusty.h" +#include "mem_map_linux.h" + namespace scudo { // This will be deprecated when every allocator has been supported by each @@ -71,7 +73,7 @@ }; #if SCUDO_LINUX -using ReservedMapT = DefaultReservedMap; +using ReservedMapT = ReservedMapLinux; using MemMapT = ReservedMapT::MemMapT; #elif SCUDO_FUCHSIA using ReservedMapT = DefaultReservedMap; diff --git a/compiler-rt/lib/scudo/standalone/mem_map.h b/compiler-rt/lib/scudo/standalone/mem_map_linux.h copy from compiler-rt/lib/scudo/standalone/mem_map.h copy to compiler-rt/lib/scudo/standalone/mem_map_linux.h --- a/compiler-rt/lib/scudo/standalone/mem_map.h +++ b/compiler-rt/lib/scudo/standalone/mem_map_linux.h @@ -1,4 +1,4 @@ -//===-- mem_map.h -----------------------------------------------*- C++ -*-===// +//===-- mem_map_linux.h -----------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,28 +6,22 @@ // //===----------------------------------------------------------------------===// -#ifndef SCUDO_MEM_MAP_H_ -#define SCUDO_MEM_MAP_H_ +#ifndef SCUDO_MEM_MAP_LINUX_H_ +#define SCUDO_MEM_MAP_LINUX_H_ -#include "mem_map_base.h" +#include "platform.h" -#include "common.h" -#include "internal_defs.h" +#if SCUDO_LINUX -// TODO: This is only used for `MapPlatformData`. Remove these includes when we -// have all three platform specific `MemMap` and `ReservedMap` implementations. -#include "fuchsia.h" -#include "linux.h" -#include "trusty.h" +#include "common.h" +#include "mem_map_base.h" namespace scudo { -// This will be deprecated when every allocator has been supported by each -// platform's `MemMap` implementation. -class DefaultMemMap final : public MemMapBase { +class MemMapLinux final : public MemMapBase { public: - constexpr DefaultMemMap() = default; - DefaultMemMap(uptr Base, uptr Capacity) + constexpr MemMapLinux() = default; + MemMapLinux(uptr Base, uptr Capacity) : MapBase(Base), MapCapacity(Capacity) {} // Impls for base functions. @@ -42,18 +36,15 @@ uptr getMapBaseImpl() { return MapBase; } uptr getMapCapacityImpl() { return MapCapacity; } - void setMapPlatformData(MapPlatformData &NewData) { Data = NewData; } - private: uptr MapBase = 0; uptr MapCapacity = 0; - MapPlatformData Data = {}; }; // This will be deprecated when every allocator has been supported by each // platform's `MemMap` implementation. -class DefaultReservedMap final - : public ReservedMap { +class ReservedMapLinux final + : public ReservedMap { public: // The following threes are the Impls for function in `MemMapBase`. uptr getMapBaseImpl() { return MapBase; } @@ -67,23 +58,10 @@ private: uptr MapBase = 0; uptr MapCapacity = 0; - MapPlatformData Data = {}; }; -#if SCUDO_LINUX -using ReservedMapT = DefaultReservedMap; -using MemMapT = ReservedMapT::MemMapT; -#elif SCUDO_FUCHSIA -using ReservedMapT = DefaultReservedMap; -using MemMapT = ReservedMapT::MemMapT; -#elif SCUDO_TRUSTY -using ReservedMapT = DefaultReservedMap; -using MemMapT = ReservedMapT::MemMapT; -#else -#error \ - "Unsupported platform, please implement the ReservedMap for your platform!" -#endif - } // namespace scudo -#endif // SCUDO_MEM_MAP_H_ +#endif // SCUDO_LINUX + +#endif // SCUDO_MEM_MAP_LINUX_H_ diff --git a/compiler-rt/lib/scudo/standalone/mem_map_linux.cpp b/compiler-rt/lib/scudo/standalone/mem_map_linux.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/lib/scudo/standalone/mem_map_linux.cpp @@ -0,0 +1,152 @@ +//===-- mem_map_linux.cpp ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "platform.h" + +#if SCUDO_LINUX + +#include "mem_map_linux.h" + +#include "common.h" +#include "internal_defs.h" +#include "linux.h" +#include "mutex.h" +#include "string_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if SCUDO_ANDROID +#include +// Definitions of prctl arguments to set a vma name in Android kernels. +#define ANDROID_PR_SET_VMA 0x53564d41 +#define ANDROID_PR_SET_VMA_ANON_NAME 0 +#endif + +namespace scudo { + +static void *mmapWrapper(uptr Addr, uptr Size, const char *Name, uptr Flags) { + int MmapFlags = MAP_PRIVATE | MAP_ANONYMOUS; + int MmapProt; + if (Flags & MAP_NOACCESS) { + MmapFlags |= MAP_NORESERVE; + MmapProt = PROT_NONE; + } else { + MmapProt = PROT_READ | PROT_WRITE; + } +#if defined(__aarch64__) +#ifndef PROT_MTE +#define PROT_MTE 0x20 +#endif + if (Flags & MAP_MEMTAG) + MmapProt |= PROT_MTE; +#endif + if (Addr) + MmapFlags |= MAP_FIXED; + void *P = + mmap(reinterpret_cast(Addr), Size, MmapProt, MmapFlags, -1, 0); + if (P == MAP_FAILED) { + if (!(Flags & MAP_ALLOWNOMEM) || errno != ENOMEM) + dieOnMapUnmapError(errno == ENOMEM ? Size : 0); + return nullptr; + } +#if SCUDO_ANDROID + if (Name) + prctl(ANDROID_PR_SET_VMA, ANDROID_PR_SET_VMA_ANON_NAME, P, Size, Name); +#else + (void)Name; +#endif + + return P; +} + +bool MemMapLinux::mapImpl(uptr Addr, uptr Size, const char *Name, uptr Flags) { + void *P = mmapWrapper(Addr, Size, Name, Flags); + if (P == nullptr) + return false; + + MapBase = reinterpret_cast(P); + MapCapacity = Size; + return true; +} + +void MemMapLinux::unmapImpl(uptr Addr, uptr Size, UNUSED uptr Flags) { + if (Size == MapCapacity) { + MapBase = MapCapacity = 0; + } else { + if (MapBase == Addr) + MapBase = Addr + Size; + MapCapacity -= Size; + } + + if (munmap(reinterpret_cast(Addr), Size) != 0) + dieOnMapUnmapError(); +} + +bool MemMapLinux::remapImpl(uptr Addr, uptr Size, const char *Name, + uptr Flags) { + void *P = mmapWrapper(Addr, Size, Name, Flags); + if (reinterpret_cast(P) != Addr) + dieOnMapUnmapError(); + return true; +} + +void MemMapLinux::setMemoryPermissionImpl(uptr Addr, uptr Size, uptr Flags) { + int Prot = (Flags & MAP_NOACCESS) ? PROT_NONE : (PROT_READ | PROT_WRITE); + if (mprotect(reinterpret_cast(Addr), Size, Prot) != 0) + dieOnMapUnmapError(); +} + +void MemMapLinux::releaseAndZeroPagesToOSImpl(uptr From, uptr Size) { + void *Addr = reinterpret_cast(From); + + while (madvise(Addr, Size, MADV_DONTNEED) == -1 && errno == EAGAIN) { + } +} + +void ReservedMapLinux::unmapImpl(uptr Addr, uptr Size, UNUSED uptr Flags) { + if (Size == MapCapacity) { + MapBase = MapCapacity = 0; + } else { + if (MapBase == Addr) + MapBase = Addr + Size; + MapCapacity -= Size; + } + + if (munmap(reinterpret_cast(Addr), Size) != 0) + dieOnMapUnmapError(); +} + +void ReservedMapLinux::reserveImpl(uptr Addr, uptr Size, const char *Name, + uptr Flags) { + ReservedMapLinux::MemMapT MemMap; + if (!MemMap.map(Addr, Size, Name, Flags | MAP_NOACCESS)) + return; + + MapBase = MemMap.getMapBase(); + MapCapacity = MemMap.getMapCapacity(); +} + +ReservedMapLinux::MemMapT ReservedMapLinux::allocateImpl(uptr Addr, uptr Size) { + return ReservedMapLinux::MemMapT(Addr, Size); +} + +} // namespace scudo + +#endif // SCUDO_LINUX