[libc] Add sys/mman syscall wrappers (#195103)

Added ErrorOr-returning syscall wrappers for mmap, munmap, mprotect, and
pkey_mprotect in src/__support/OSUtil/linux/syscall_wrappers/. Migrated
the sys/mman Linux entrypoint implementations to use them, following the
design in libc/docs/dev/syscall_wrapper_refactor.rst.

Removed the shared mprotect_common.h in favour of per-syscall wrapper
headers. Added hdr/sys_mman_macros.h proxy header.
This commit is contained in:
Jeff Bailey
2026-04-30 18:09:10 +01:00
committed by GitHub
parent a23ddcd3b2
commit 699d3bfdba
13 changed files with 277 additions and 162 deletions

View File

@@ -185,6 +185,15 @@ add_proxy_header_library(
libc.include.llvm-libc-macros.sys_stat_macros
)
add_proxy_header_library(
sys_mman_macros
HDRS
sys_mman_macros.h
FULL_BUILD_DEPENDS
libc.include.sys_mman
libc.include.llvm-libc-macros.sys_mman_macros
)
add_header_library(unistd_overlay HDRS unistd_overlay.h)
add_proxy_header_library(
unistd_macros

View File

@@ -0,0 +1,22 @@
//===-- Definition of macros from sys/mman.h ------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_SYS_MMAN_MACROS_H
#define LLVM_LIBC_HDR_SYS_MMAN_MACROS_H
#ifdef LIBC_FULL_BUILD
#include "include/llvm-libc-macros/sys-mman-macros.h"
#else // Overlay mode
#include <sys/mman.h>
#endif // LLVM_LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_SYS_MMAN_MACROS_H

View File

@@ -185,3 +185,53 @@ add_header_library(
libc.hdr.types.struct_timespec
libc.include.sys_syscall
)
add_header_library(
mmap
HDRS
mmap.h
DEPENDS
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
libc.src.__support.macros.config
libc.hdr.types.off_t
libc.include.sys_syscall
)
add_header_library(
munmap
HDRS
munmap.h
DEPENDS
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
libc.src.__support.macros.config
libc.include.sys_syscall
)
add_header_library(
mprotect
HDRS
mprotect.h
DEPENDS
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
libc.src.__support.macros.config
libc.include.sys_syscall
)
add_header_library(
pkey_mprotect
HDRS
pkey_mprotect.h
DEPENDS
libc.src.__support.OSUtil.osutil
libc.src.__support.common
libc.src.__support.error_or
libc.src.__support.macros.config
libc.hdr.errno_macros
libc.include.sys_syscall
)

View File

@@ -0,0 +1,59 @@
//===-- Syscall wrapper for mmap --------------------------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MMAP_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MMAP_H
#include "hdr/types/off_t.h"
#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl, linux_utils::is_valid_mmap
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
#include <linux/param.h> // For EXEC_PAGESIZE
#include <sys/syscall.h> // For syscall numbers
namespace LIBC_NAMESPACE_DECL {
namespace linux_syscalls {
LIBC_INLINE ErrorOr<void *> mmap(void *addr, size_t size, int prot, int flags,
int fd, off_t offset) {
// TODO: Perform POSIX-prescribed argument validation not done by the
// linux syscall.
// EXEC_PAGESIZE is used for the page size. While this is OK for x86_64,
// it might not be correct in general.
// TODO: Use pagesize read from the ELF aux vector instead of
// EXEC_PAGESIZE.
#ifdef SYS_mmap2
offset /= EXEC_PAGESIZE;
long syscall_number = SYS_mmap2;
#elif defined(SYS_mmap)
long syscall_number = SYS_mmap;
#else
#error "mmap or mmap2 syscalls not available."
#endif
// Explicit cast to silence "implicit conversion loses integer precision"
// warnings when compiling for 32-bit systems.
long ret =
syscall_impl<long>(syscall_number, reinterpret_cast<long>(addr), size,
prot, flags, fd, static_cast<long>(offset));
// A negative return value from the syscall can also be an error-free
// value returned by the syscall. However, since a valid return address
// cannot be within the last page, a return value corresponding to a
// location in the last page is an error value.
if (!linux_utils::is_valid_mmap(ret))
return Error(-static_cast<int>(ret));
return reinterpret_cast<void *>(ret);
}
} // namespace linux_syscalls
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MMAP_H

View File

@@ -0,0 +1,32 @@
//===-- Syscall wrapper for mprotect ----------------------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MPROTECT_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MPROTECT_H
#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
#include <sys/syscall.h> // For syscall numbers
namespace LIBC_NAMESPACE_DECL {
namespace linux_syscalls {
LIBC_INLINE ErrorOr<int> mprotect(void *addr, size_t size, int prot) {
int ret =
syscall_impl<int>(SYS_mprotect, reinterpret_cast<long>(addr), size, prot);
if (ret < 0)
return Error(-ret);
return ret;
}
} // namespace linux_syscalls
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MPROTECT_H

View File

@@ -0,0 +1,31 @@
//===-- Syscall wrapper for munmap ------------------------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MUNMAP_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MUNMAP_H
#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
#include <sys/syscall.h> // For syscall numbers
namespace LIBC_NAMESPACE_DECL {
namespace linux_syscalls {
LIBC_INLINE ErrorOr<int> munmap(void *addr, size_t size) {
int ret = syscall_impl<int>(SYS_munmap, reinterpret_cast<long>(addr), size);
if (ret < 0)
return Error(-ret);
return ret;
}
} // namespace linux_syscalls
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_MUNMAP_H

View File

@@ -0,0 +1,38 @@
//===-- Syscall wrapper for pkey_mprotect -----------------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PKEY_MPROTECT_H
#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PKEY_MPROTECT_H
#include "hdr/errno_macros.h"
#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/macros/config.h"
#include <sys/syscall.h> // For syscall numbers
namespace LIBC_NAMESPACE_DECL {
namespace linux_syscalls {
LIBC_INLINE ErrorOr<int> pkey_mprotect(void *addr, size_t len, int prot,
int pkey) {
#if !defined(SYS_pkey_mprotect)
return Error(ENOSYS);
#else
int ret = syscall_impl<int>(SYS_pkey_mprotect, reinterpret_cast<long>(addr),
len, prot, pkey);
if (ret < 0)
return Error(-ret);
return ret;
#endif
}
} // namespace linux_syscalls
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PKEY_MPROTECT_H

View File

@@ -25,9 +25,10 @@ add_entrypoint_object(
HDRS
../mmap.h
DEPENDS
libc.include.sys_mman
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.hdr.sys_mman_macros
libc.hdr.types.size_t
libc.hdr.types.off_t
libc.src.__support.OSUtil.linux.syscall_wrappers.mmap
libc.src.errno.errno
)
@@ -51,23 +52,11 @@ add_entrypoint_object(
HDRS
../munmap.h
DEPENDS
libc.include.sys_mman
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.hdr.types.size_t
libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
libc.src.errno.errno
)
add_header_library(
mprotect_common
HDRS
mprotect_common.h
DEPENDS
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.errno
libc.src.__support.error_or
)
add_entrypoint_object(
mprotect
SRCS
@@ -75,11 +64,9 @@ add_entrypoint_object(
HDRS
../mprotect.h
DEPENDS
libc.include.sys_mman
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.hdr.types.size_t
libc.src.__support.OSUtil.linux.syscall_wrappers.mprotect
libc.src.errno.errno
.mprotect_common
)
add_entrypoint_object(
@@ -240,11 +227,10 @@ add_entrypoint_object(
HDRS
../pkey_mprotect.h
DEPENDS
libc.include.sys_mman
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.hdr.types.size_t
libc.src.__support.OSUtil.linux.syscall_wrappers.mprotect
libc.src.__support.OSUtil.linux.syscall_wrappers.pkey_mprotect
libc.src.errno.errno
.mprotect_common
)
add_entrypoint_object(

View File

@@ -7,61 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/sys/mman/mmap.h"
#include "hdr/sys_mman_macros.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/OSUtil/linux/syscall_wrappers/mmap.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include <linux/param.h> // For EXEC_PAGESIZE.
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
// This function is currently linux only. It has to be refactored suitably if
// mmap is to be supported on non-linux operating systems also.
LLVM_LIBC_FUNCTION(void *, mmap,
(void *addr, size_t size, int prot, int flags, int fd,
off_t offset)) {
// A lot of POSIX standard prescribed validation of the parameters is not
// done in this function as modern linux versions do it in the syscall.
// TODO: Perform argument validation not done by the linux syscall.
// EXEC_PAGESIZE is used for the page size. While this is OK for x86_64, it
// might not be correct in general.
// TODO: Use pagesize read from the ELF aux vector instead of EXEC_PAGESIZE.
#ifdef SYS_mmap2
offset /= EXEC_PAGESIZE;
long syscall_number = SYS_mmap2;
#elif defined(SYS_mmap)
long syscall_number = SYS_mmap;
#else
#error "mmap or mmap2 syscalls not available."
#endif
// We add an explicit cast to silence a "implicit conversion loses integer
// precision" warning when compiling for 32-bit systems.
long mmap_offset = static_cast<long>(offset);
long ret =
LIBC_NAMESPACE::syscall_impl(syscall_number, reinterpret_cast<long>(addr),
size, prot, flags, fd, mmap_offset);
// The mmap/mmap2 syscalls return negative values on error. These negative
// values are actually the negative values of the error codes. So, fix them
// up in case an error code is detected.
//
// A point to keep in mind for the fix up is that a negative return value
// from the syscall can also be an error-free value returned by the syscall.
// However, since a valid return address cannot be within the last page, a
// return value corresponding to a location in the last page is an error
// value.
if (!linux_utils::is_valid_mmap(ret)) {
libc_errno = static_cast<int>(-ret);
auto result = linux_syscalls::mmap(addr, size, prot, flags, fd, offset);
if (!result) {
libc_errno = result.error();
return MAP_FAILED;
}
return reinterpret_cast<void *>(ret);
return result.value();
}
} // namespace LIBC_NAMESPACE_DECL

View File

@@ -8,25 +8,20 @@
#include "src/sys/mman/mprotect.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/OSUtil/linux/syscall_wrappers/mprotect.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/sys/mman/linux/mprotect_common.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, mprotect, (void *addr, size_t size, int prot)) {
ErrorOr<int> result =
LIBC_NAMESPACE::mprotect_common::mprotect_impl(addr, size, prot);
if (!result.has_value()) {
auto result = linux_syscalls::mprotect(addr, size, prot);
if (!result) {
libc_errno = result.error();
return -1;
}
return result.value();
return 0;
}
} // namespace LIBC_NAMESPACE_DECL

View File

@@ -1,38 +0,0 @@
//===---------- Shared Linux implementation of POSIX mprotect. ------------===//
//
// 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 "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
namespace mprotect_common {
// This function is currently linux only. It has to be refactored suitably if
// mprotect is to be supported on non-linux operating systems also.
LIBC_INLINE ErrorOr<int> mprotect_impl(void *addr, size_t size, int prot) {
int ret = LIBC_NAMESPACE::syscall_impl<int>(
SYS_mprotect, reinterpret_cast<long>(addr), size, prot);
// A negative return value indicates an error with the magnitude of the
// value being the error code.
if (ret < 0) {
return Error(-ret);
}
return 0;
}
} // namespace mprotect_common
} // namespace LIBC_NAMESPACE_DECL

View File

@@ -8,28 +8,19 @@
#include "src/sys/mman/munmap.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/OSUtil/linux/syscall_wrappers/munmap.h"
#include "src/__support/common.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
// This function is currently linux only. It has to be refactored suitably if
// mmap is to be supported on non-linux operating systems also.
LLVM_LIBC_FUNCTION(int, munmap, (void *addr, size_t size)) {
int ret = LIBC_NAMESPACE::syscall_impl<int>(
SYS_munmap, reinterpret_cast<long>(addr), size);
// A negative return value indicates an error with the magnitude of the
// value being the error code.
if (ret < 0) {
libc_errno = -ret;
auto result = linux_syscalls::munmap(addr, size);
if (!result) {
libc_errno = result.error();
return -1;
}
return 0;
}

View File

@@ -8,51 +8,28 @@
#include "src/sys/mman/pkey_mprotect.h"
#include "hdr/errno_macros.h" // For ENOSYS
#include "hdr/types/size_t.h"
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
#include "src/__support/OSUtil/linux/syscall_wrappers/mprotect.h"
#include "src/__support/OSUtil/linux/syscall_wrappers/pkey_mprotect.h"
#include "src/__support/common.h"
#include "src/__support/error_or.h"
#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
#include "src/sys/mman/linux/mprotect_common.h"
#include <sys/syscall.h> // For syscall numbers.
namespace LIBC_NAMESPACE_DECL {
namespace internal {
LIBC_INLINE ErrorOr<int> pkey_mprotect_impl(void *addr, size_t len, int prot,
int pkey) {
// Fall back to mprotect if pkey is -1
// to maintain compatibility with kernel versions that don't support pkey.
if (pkey == -1) {
return LIBC_NAMESPACE::mprotect_common::mprotect_impl(addr, len, prot);
}
#if !defined(SYS_pkey_mprotect)
return Error(ENOSYS);
#else
int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_pkey_mprotect, addr, len,
prot, pkey);
if (ret < 0) {
return Error(-ret);
}
return 0;
#endif
}
} // namespace internal
LLVM_LIBC_FUNCTION(int, pkey_mprotect,
(void *addr, size_t len, int prot, int pkey)) {
ErrorOr<int> ret =
LIBC_NAMESPACE::internal::pkey_mprotect_impl(addr, len, prot, pkey);
if (!ret.has_value()) {
ErrorOr<int> ret(0);
if (pkey == -1) {
ret = linux_syscalls::mprotect(addr, len, prot);
} else {
ret = linux_syscalls::pkey_mprotect(addr, len, prot, pkey);
}
if (!ret) {
libc_errno = ret.error();
return -1;
}
return ret.value();
return 0;
}
} // namespace LIBC_NAMESPACE_DECL