From 5a6cc509215b62e94de3b798ea26944a375ce6cb Mon Sep 17 00:00:00 2001 From: Jingyu Qiu <51221277+SoftJing1@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:25:50 -0500 Subject: [PATCH] [libc] add mremap (#112804) --- libc/config/linux/aarch64/entrypoints.txt | 1 + libc/config/linux/x86_64/entrypoints.txt | 1 + libc/newhdrgen/yaml/sys/mman.yaml | 10 +++ libc/spec/linux.td | 13 +++- libc/src/sys/mman/CMakeLists.txt | 7 ++ libc/src/sys/mman/linux/CMakeLists.txt | 13 ++++ libc/src/sys/mman/linux/mremap.cpp | 45 +++++++++++++ libc/src/sys/mman/mremap.h | 22 +++++++ libc/test/src/sys/mman/linux/CMakeLists.txt | 15 +++++ libc/test/src/sys/mman/linux/mremap_test.cpp | 68 ++++++++++++++++++++ 10 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 libc/src/sys/mman/linux/mremap.cpp create mode 100644 libc/src/sys/mman/mremap.h create mode 100644 libc/test/src/sys/mman/linux/mremap_test.cpp diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index bf60d6f00052..571527426de3 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -245,6 +245,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.mman.mlock2 libc.src.sys.mman.mlockall libc.src.sys.mman.mmap + libc.src.sys.mman.mremap libc.src.sys.mman.mprotect libc.src.sys.mman.msync libc.src.sys.mman.munlock diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index b8c2a82a4d5b..9a4a0ff9e75a 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -244,6 +244,7 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.sys.mman.mlock2 libc.src.sys.mman.mlockall libc.src.sys.mman.mmap + libc.src.sys.mman.mremap libc.src.sys.mman.mprotect libc.src.sys.mman.msync libc.src.sys.mman.munlock diff --git a/libc/newhdrgen/yaml/sys/mman.yaml b/libc/newhdrgen/yaml/sys/mman.yaml index 7c4fb1ef09e7..962ca3591917 100644 --- a/libc/newhdrgen/yaml/sys/mman.yaml +++ b/libc/newhdrgen/yaml/sys/mman.yaml @@ -55,6 +55,16 @@ functions: - type: int - type: int - type: off_t + - name: mremap + standards: + - POSIX + return_type: void * + arguments: + - type: void * + - type: size_t + - type: size_t + - type: int + - type: '...' - name: mprotect standards: - POSIX diff --git a/libc/spec/linux.td b/libc/spec/linux.td index c8604e8184f6..9b5dc8e30c95 100644 --- a/libc/spec/linux.td +++ b/libc/spec/linux.td @@ -103,7 +103,7 @@ def Linux : StandardSpec<"Linux"> { ArgSpec, ] >, - FunctionSpec< + FunctionSpec< "remap_file_pages", RetValSpec, [ @@ -114,6 +114,17 @@ def Linux : StandardSpec<"Linux"> { ArgSpec, ] >, + FunctionSpec< + "mremap", + RetValSpec, + [ + ArgSpec, + ArgSpec, + ArgSpec, + ArgSpec, + ArgSpec, + ] + >, ] // Functions >; diff --git a/libc/src/sys/mman/CMakeLists.txt b/libc/src/sys/mman/CMakeLists.txt index 4ea43e14be02..4d4c2ad37605 100644 --- a/libc/src/sys/mman/CMakeLists.txt +++ b/libc/src/sys/mman/CMakeLists.txt @@ -106,3 +106,10 @@ add_entrypoint_object( DEPENDS .${LIBC_TARGET_OS}.shm_unlink ) + +add_entrypoint_object( + mremap + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.mremap +) diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt index 47c16f79bc8d..89a0ad1527a0 100644 --- a/libc/src/sys/mman/linux/CMakeLists.txt +++ b/libc/src/sys/mman/linux/CMakeLists.txt @@ -24,6 +24,19 @@ add_entrypoint_object( libc.src.errno.errno ) +add_entrypoint_object( + mremap + SRCS + mremap.cpp + HDRS + ../mremap.h + DEPENDS + libc.include.sys_mman + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + add_entrypoint_object( munmap SRCS diff --git a/libc/src/sys/mman/linux/mremap.cpp b/libc/src/sys/mman/linux/mremap.cpp new file mode 100644 index 000000000000..38bcfce833d3 --- /dev/null +++ b/libc/src/sys/mman/linux/mremap.cpp @@ -0,0 +1,45 @@ +//===---------- Linux implementation of the POSIX mremap function----------===// +// +// 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/sys/mman/mremap.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" + +#include "src/__support/macros/config.h" +#include "src/errno/libc_errno.h" +#include // For EXEC_PAGESIZE. +#include +#include // For syscall numbers. + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(void *, mremap, + (void *old_address, size_t old_size, size_t new_size, + int flags, ... /* void *new_address */)) { + + long ret = 0; + void *new_address = nullptr; + if (flags & MREMAP_FIXED) { + va_list varargs; + va_start(varargs, flags); + new_address = va_arg(varargs, void *); + va_end(varargs); + } + ret = LIBC_NAMESPACE::syscall_impl(SYS_mremap, old_address, old_size, + new_size, flags, new_address); + + if (ret < 0 && ret > -EXEC_PAGESIZE) { + libc_errno = static_cast(-ret); + return MAP_FAILED; + } + + return reinterpret_cast(ret); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/sys/mman/mremap.h b/libc/src/sys/mman/mremap.h new file mode 100644 index 000000000000..208946bc58a2 --- /dev/null +++ b/libc/src/sys/mman/mremap.h @@ -0,0 +1,22 @@ +//===-- Implementation header for mremap function -------------------------===// +// +// 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_SYS_MMAN_MREMAP_H +#define LLVM_LIBC_SRC_SYS_MMAN_MREMAP_H + +#include "src/__support/macros/config.h" +#include // For size_t and off_t + +namespace LIBC_NAMESPACE_DECL { + +void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, + ... /* void *new_address */); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_SYS_MMAN_MREMAP_H diff --git a/libc/test/src/sys/mman/linux/CMakeLists.txt b/libc/test/src/sys/mman/linux/CMakeLists.txt index 69263986cc57..44ed11aadfe8 100644 --- a/libc/test/src/sys/mman/linux/CMakeLists.txt +++ b/libc/test/src/sys/mman/linux/CMakeLists.txt @@ -14,6 +14,21 @@ add_libc_unittest( libc.test.UnitTest.ErrnoSetterMatcher ) +add_libc_unittest( + mremap_test + SUITE + libc_sys_mman_unittests + SRCS + mremap_test.cpp + DEPENDS + libc.include.sys_mman + libc.src.errno.errno + libc.src.sys.mman.mmap + libc.src.sys.mman.mremap + libc.src.sys.mman.munmap + libc.test.UnitTest.ErrnoSetterMatcher +) + if (NOT LLVM_USE_SANITIZER) add_libc_unittest( mprotect_test diff --git a/libc/test/src/sys/mman/linux/mremap_test.cpp b/libc/test/src/sys/mman/linux/mremap_test.cpp new file mode 100644 index 000000000000..12e448558842 --- /dev/null +++ b/libc/test/src/sys/mman/linux/mremap_test.cpp @@ -0,0 +1,68 @@ +//===-- Unittests for mremap ----------------------------------------------===// +// +// 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/errno/libc_errno.h" +#include "src/sys/mman/mmap.h" +#include "src/sys/mman/mremap.h" +#include "src/sys/mman/munmap.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" + +#include + +using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; +using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + +TEST(LlvmLibcMremapTest, NoError) { + size_t initial_size = 128; + size_t new_size = 256; + LIBC_NAMESPACE::libc_errno = 0; + + // Allocate memory using mmap. + void *addr = + LIBC_NAMESPACE::mmap(nullptr, initial_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_ERRNO_SUCCESS(); + EXPECT_NE(addr, MAP_FAILED); + + int *array = reinterpret_cast(addr); + // Writing to the memory should not crash the test. + array[0] = 123; + EXPECT_EQ(array[0], 123); + + // Re-map the memory using mremap with an increased size. + void *new_addr = + LIBC_NAMESPACE::mremap(addr, initial_size, new_size, MREMAP_MAYMOVE); + ASSERT_ERRNO_SUCCESS(); + EXPECT_NE(new_addr, MAP_FAILED); + EXPECT_EQ(reinterpret_cast(new_addr)[0], + 123); // Verify data is preserved. + + // Clean up memory by unmapping it. + EXPECT_THAT(LIBC_NAMESPACE::munmap(new_addr, new_size), Succeeds()); +} + +TEST(LlvmLibcMremapTest, Error_InvalidSize) { + size_t initial_size = 128; + LIBC_NAMESPACE::libc_errno = 0; + + // Allocate memory using mmap. + void *addr = + LIBC_NAMESPACE::mmap(nullptr, initial_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + ASSERT_ERRNO_SUCCESS(); + EXPECT_NE(addr, MAP_FAILED); + + // Attempt to re-map the memory with an invalid new size (0). + void *new_addr = + LIBC_NAMESPACE::mremap(addr, initial_size, 0, MREMAP_MAYMOVE); + EXPECT_THAT(new_addr, Fails(EINVAL, MAP_FAILED)); + + // Clean up the original mapping. + EXPECT_THAT(LIBC_NAMESPACE::munmap(addr, initial_size), Succeeds()); +}