Skip to content

Commit 5a6cc50

Browse files
authored
[libc] add mremap (#112804)
1 parent 38cc03f commit 5a6cc50

File tree

10 files changed

+194
-1
lines changed

10 files changed

+194
-1
lines changed

libc/config/linux/aarch64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ set(TARGET_LIBC_ENTRYPOINTS
245245
libc.src.sys.mman.mlock2
246246
libc.src.sys.mman.mlockall
247247
libc.src.sys.mman.mmap
248+
libc.src.sys.mman.mremap
248249
libc.src.sys.mman.mprotect
249250
libc.src.sys.mman.msync
250251
libc.src.sys.mman.munlock

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ set(TARGET_LIBC_ENTRYPOINTS
244244
libc.src.sys.mman.mlock2
245245
libc.src.sys.mman.mlockall
246246
libc.src.sys.mman.mmap
247+
libc.src.sys.mman.mremap
247248
libc.src.sys.mman.mprotect
248249
libc.src.sys.mman.msync
249250
libc.src.sys.mman.munlock

libc/newhdrgen/yaml/sys/mman.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ functions:
5555
- type: int
5656
- type: int
5757
- type: off_t
58+
- name: mremap
59+
standards:
60+
- POSIX
61+
return_type: void *
62+
arguments:
63+
- type: void *
64+
- type: size_t
65+
- type: size_t
66+
- type: int
67+
- type: '...'
5868
- name: mprotect
5969
standards:
6070
- POSIX

libc/spec/linux.td

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def Linux : StandardSpec<"Linux"> {
103103
ArgSpec<UnsignedIntType>,
104104
]
105105
>,
106-
FunctionSpec<
106+
FunctionSpec<
107107
"remap_file_pages",
108108
RetValSpec<IntType>,
109109
[
@@ -114,6 +114,17 @@ def Linux : StandardSpec<"Linux"> {
114114
ArgSpec<IntType>,
115115
]
116116
>,
117+
FunctionSpec<
118+
"mremap",
119+
RetValSpec<VoidPtr>,
120+
[
121+
ArgSpec<VoidPtr>,
122+
ArgSpec<SizeTType>,
123+
ArgSpec<SizeTType>,
124+
ArgSpec<IntType>,
125+
ArgSpec<VarArgType>,
126+
]
127+
>,
117128
] // Functions
118129
>;
119130

libc/src/sys/mman/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,10 @@ add_entrypoint_object(
106106
DEPENDS
107107
.${LIBC_TARGET_OS}.shm_unlink
108108
)
109+
110+
add_entrypoint_object(
111+
mremap
112+
ALIAS
113+
DEPENDS
114+
.${LIBC_TARGET_OS}.mremap
115+
)

libc/src/sys/mman/linux/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,19 @@ add_entrypoint_object(
2424
libc.src.errno.errno
2525
)
2626

27+
add_entrypoint_object(
28+
mremap
29+
SRCS
30+
mremap.cpp
31+
HDRS
32+
../mremap.h
33+
DEPENDS
34+
libc.include.sys_mman
35+
libc.include.sys_syscall
36+
libc.src.__support.OSUtil.osutil
37+
libc.src.errno.errno
38+
)
39+
2740
add_entrypoint_object(
2841
munmap
2942
SRCS

libc/src/sys/mman/linux/mremap.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//===---------- Linux implementation of the POSIX mremap function----------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/sys/mman/mremap.h"
10+
11+
#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
12+
#include "src/__support/common.h"
13+
14+
#include "src/__support/macros/config.h"
15+
#include "src/errno/libc_errno.h"
16+
#include <linux/param.h> // For EXEC_PAGESIZE.
17+
#include <stdarg.h>
18+
#include <sys/syscall.h> // For syscall numbers.
19+
20+
namespace LIBC_NAMESPACE_DECL {
21+
22+
LLVM_LIBC_FUNCTION(void *, mremap,
23+
(void *old_address, size_t old_size, size_t new_size,
24+
int flags, ... /* void *new_address */)) {
25+
26+
long ret = 0;
27+
void *new_address = nullptr;
28+
if (flags & MREMAP_FIXED) {
29+
va_list varargs;
30+
va_start(varargs, flags);
31+
new_address = va_arg(varargs, void *);
32+
va_end(varargs);
33+
}
34+
ret = LIBC_NAMESPACE::syscall_impl<long>(SYS_mremap, old_address, old_size,
35+
new_size, flags, new_address);
36+
37+
if (ret < 0 && ret > -EXEC_PAGESIZE) {
38+
libc_errno = static_cast<int>(-ret);
39+
return MAP_FAILED;
40+
}
41+
42+
return reinterpret_cast<void *>(ret);
43+
}
44+
45+
} // namespace LIBC_NAMESPACE_DECL

libc/src/sys/mman/mremap.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===-- Implementation header for mremap function -------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_SYS_MMAN_MREMAP_H
10+
#define LLVM_LIBC_SRC_SYS_MMAN_MREMAP_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include <sys/mman.h> // For size_t and off_t
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
void *mremap(void *old_address, size_t old_size, size_t new_size, int flags,
18+
... /* void *new_address */);
19+
20+
} // namespace LIBC_NAMESPACE_DECL
21+
22+
#endif // LLVM_LIBC_SRC_SYS_MMAN_MREMAP_H

libc/test/src/sys/mman/linux/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ add_libc_unittest(
1414
libc.test.UnitTest.ErrnoSetterMatcher
1515
)
1616

17+
add_libc_unittest(
18+
mremap_test
19+
SUITE
20+
libc_sys_mman_unittests
21+
SRCS
22+
mremap_test.cpp
23+
DEPENDS
24+
libc.include.sys_mman
25+
libc.src.errno.errno
26+
libc.src.sys.mman.mmap
27+
libc.src.sys.mman.mremap
28+
libc.src.sys.mman.munmap
29+
libc.test.UnitTest.ErrnoSetterMatcher
30+
)
31+
1732
if (NOT LLVM_USE_SANITIZER)
1833
add_libc_unittest(
1934
mprotect_test
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===-- Unittests for mremap ----------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "src/errno/libc_errno.h"
10+
#include "src/sys/mman/mmap.h"
11+
#include "src/sys/mman/mremap.h"
12+
#include "src/sys/mman/munmap.h"
13+
#include "test/UnitTest/ErrnoSetterMatcher.h"
14+
#include "test/UnitTest/Test.h"
15+
16+
#include <sys/mman.h>
17+
18+
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
19+
using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
20+
21+
TEST(LlvmLibcMremapTest, NoError) {
22+
size_t initial_size = 128;
23+
size_t new_size = 256;
24+
LIBC_NAMESPACE::libc_errno = 0;
25+
26+
// Allocate memory using mmap.
27+
void *addr =
28+
LIBC_NAMESPACE::mmap(nullptr, initial_size, PROT_READ | PROT_WRITE,
29+
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
30+
ASSERT_ERRNO_SUCCESS();
31+
EXPECT_NE(addr, MAP_FAILED);
32+
33+
int *array = reinterpret_cast<int *>(addr);
34+
// Writing to the memory should not crash the test.
35+
array[0] = 123;
36+
EXPECT_EQ(array[0], 123);
37+
38+
// Re-map the memory using mremap with an increased size.
39+
void *new_addr =
40+
LIBC_NAMESPACE::mremap(addr, initial_size, new_size, MREMAP_MAYMOVE);
41+
ASSERT_ERRNO_SUCCESS();
42+
EXPECT_NE(new_addr, MAP_FAILED);
43+
EXPECT_EQ(reinterpret_cast<int *>(new_addr)[0],
44+
123); // Verify data is preserved.
45+
46+
// Clean up memory by unmapping it.
47+
EXPECT_THAT(LIBC_NAMESPACE::munmap(new_addr, new_size), Succeeds());
48+
}
49+
50+
TEST(LlvmLibcMremapTest, Error_InvalidSize) {
51+
size_t initial_size = 128;
52+
LIBC_NAMESPACE::libc_errno = 0;
53+
54+
// Allocate memory using mmap.
55+
void *addr =
56+
LIBC_NAMESPACE::mmap(nullptr, initial_size, PROT_READ | PROT_WRITE,
57+
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
58+
ASSERT_ERRNO_SUCCESS();
59+
EXPECT_NE(addr, MAP_FAILED);
60+
61+
// Attempt to re-map the memory with an invalid new size (0).
62+
void *new_addr =
63+
LIBC_NAMESPACE::mremap(addr, initial_size, 0, MREMAP_MAYMOVE);
64+
EXPECT_THAT(new_addr, Fails(EINVAL, MAP_FAILED));
65+
66+
// Clean up the original mapping.
67+
EXPECT_THAT(LIBC_NAMESPACE::munmap(addr, initial_size), Succeeds());
68+
}

0 commit comments

Comments
 (0)