Files
asterinas/test/apps/mmap/mmap_and_mremap.c
2025-06-24 10:24:13 +08:00

109 lines
3.3 KiB
C

// SPDX-License-Identifier: MPL-2.0
#define _GNU_SOURCE
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include "../network/test.h"
#define PAGE_SIZE 4096
FN_TEST(mremap)
{
char *addr = TEST_SUCC(mmap(NULL, 3 * PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
TEST_SUCC(munmap(addr + 2 * PAGE_SIZE, PAGE_SIZE));
// The old address is not page-aligned.
TEST_ERRNO(mremap(addr + 1, PAGE_SIZE, PAGE_SIZE, 0), EINVAL);
// The old size or the new size is not page-aligned.
TEST_RES(mremap(addr, 1, PAGE_SIZE, 0), _ret == addr);
TEST_RES(mremap(addr, PAGE_SIZE, 1, 0), _ret == addr);
// The new address is not page-aligned.
TEST_ERRNO(mremap(addr, PAGE_SIZE, PAGE_SIZE,
MREMAP_MAYMOVE | MREMAP_FIXED,
addr + 2 * PAGE_SIZE + 1),
EINVAL);
// The flags or the combination of the flags is invalid.
TEST_ERRNO(mremap(addr, PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED,
addr + 2 * PAGE_SIZE),
EINVAL);
TEST_ERRNO(mremap(addr, PAGE_SIZE, PAGE_SIZE, ~0, addr + 2 * PAGE_SIZE),
EINVAL);
// Copying a private mapping should not be allowed. See the "BUGS" section at
// <https://man7.org/linux/man-pages/man2/mremap.2.html>.
TEST_ERRNO(mremap(addr, 0, PAGE_SIZE, 0), EINVAL);
// There is no enough room to expand the mapping.
// FIXME: Asterinas returns EACCESS here, which is not a correct error code.
// TEST_ERRNO(mremap(addr, PAGE_SIZE, 2 * PAGE_SIZE, 0), ENOMEM);
TEST_SUCC(munmap(addr, 2 * PAGE_SIZE));
}
END_TEST()
const char *content = "kjfkljk*wigo&h";
#define CHECK_MM(func) CHECK_WITH(func, _ret != MAP_FAILED)
FN_TEST(mmap_and_mremap)
{
char *addr = CHECK_MM(mmap(NULL, 3 * PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
TEST_SUCC(munmap(addr, 3 * PAGE_SIZE));
addr = CHECK_MM(mmap(addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0));
strcpy(addr, content);
char *addr2 = CHECK_MM(
mmap(addr + 2 * PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0));
char *new_addr = CHECK_MM(
mremap(addr, PAGE_SIZE, 3 * PAGE_SIZE, MREMAP_MAYMOVE));
// The following operation (if uncommented) would cause a segmentation fault.
// strcpy(addr, "Writing to old address");
TEST_RES(strcmp(new_addr, content), _ret == 0);
strcpy(new_addr + PAGE_SIZE, "Writing to page 2 (new)");
strcpy(new_addr + 2 * PAGE_SIZE, "Writing to page 3 (new)");
TEST_SUCC(munmap(new_addr, 3 * PAGE_SIZE));
TEST_SUCC(munmap(addr2, PAGE_SIZE));
}
END_TEST()
FN_TEST(mmap_and_mremap_fixed)
{
char *addr1 = CHECK_MM(mmap(NULL, PAGE_SIZE * 2, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
strcpy(addr1, content);
// Unmap a target region to ensure we know it's free
char *addr2 = addr1 + PAGE_SIZE;
TEST_SUCC(munmap(addr2, PAGE_SIZE)); // free it for mremap
// Remap from the first address to the second address
CHECK_WITH(mremap(addr1, PAGE_SIZE, PAGE_SIZE,
MREMAP_MAYMOVE | MREMAP_FIXED, addr2),
_ret == addr2);
TEST_RES(strcmp(addr2, content), _ret == 0);
// Remap from the second address to the first address
CHECK_WITH(mremap(addr2, PAGE_SIZE, PAGE_SIZE,
MREMAP_MAYMOVE | MREMAP_FIXED, addr1),
_ret == addr1);
TEST_RES(strcmp(addr1, content), _ret == 0);
TEST_SUCC(munmap(addr1, PAGE_SIZE));
}
END_TEST()