183 lines · cpp
1//===-- Unittests for mlock -----------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9// TODO: Simplify these tests and split them up. mlock, mlock2, mlockall,10// munlock, and munlockall should have separate test files which only need to11// check our code paths (succeeds and errors).12 13#include "src/__support/OSUtil/syscall.h" // For internal syscall function.14#include "src/__support/libc_errno.h"15#include "src/sys/mman/madvise.h"16#include "src/sys/mman/mincore.h"17#include "src/sys/mman/mlock.h"18#include "src/sys/mman/mlock2.h"19#include "src/sys/mman/mlockall.h"20#include "src/sys/mman/mmap.h"21#include "src/sys/mman/munlock.h"22#include "src/sys/mman/munlockall.h"23#include "src/sys/mman/munmap.h"24#include "src/sys/resource/getrlimit.h"25#include "src/unistd/sysconf.h"26#include "test/UnitTest/ErrnoCheckingTest.h"27#include "test/UnitTest/ErrnoSetterMatcher.h"28#include "test/UnitTest/Test.h"29 30#include <sys/syscall.h>31 32const size_t PAGE_SIZE = LIBC_NAMESPACE::sysconf(_SC_PAGESIZE);33 34using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;35using LlvmLibcMlockTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;36 37struct PageHolder {38 size_t size;39 void *addr;40 41 PageHolder()42 : size(PAGE_SIZE),43 addr(LIBC_NAMESPACE::mmap(nullptr, size, PROT_READ | PROT_WRITE,44 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) {}45 ~PageHolder() {46 if (addr != MAP_FAILED)47 LIBC_NAMESPACE::munmap(addr, size);48 }49 50 char &operator[](size_t i) { return reinterpret_cast<char *>(addr)[i]; }51 52 bool is_valid() { return addr != MAP_FAILED; }53};54 55static bool is_permitted_size(size_t size) {56 rlimit rlimits;57 LIBC_NAMESPACE::getrlimit(RLIMIT_MEMLOCK, &rlimits);58 return size <= static_cast<size_t>(rlimits.rlim_cur);59}60 61TEST_F(LlvmLibcMlockTest, UnMappedMemory) {62 EXPECT_THAT(LIBC_NAMESPACE::mlock(nullptr, 1024), Fails(ENOMEM));63 EXPECT_THAT(LIBC_NAMESPACE::munlock(nullptr, 1024), Fails(ENOMEM));64}65 66TEST_F(LlvmLibcMlockTest, Overflow) {67 PageHolder holder;68 EXPECT_TRUE(holder.is_valid());69 size_t negative_size = -holder.size;70 int expected_errno = is_permitted_size(negative_size) ? EINVAL : ENOMEM;71 EXPECT_THAT(LIBC_NAMESPACE::mlock(holder.addr, negative_size),72 Fails(expected_errno));73 EXPECT_THAT(LIBC_NAMESPACE::munlock(holder.addr, negative_size),74 Fails(EINVAL));75}76 77#ifdef SYS_mlock278TEST_F(LlvmLibcMlockTest, MLock2) {79 PageHolder holder;80 EXPECT_TRUE(holder.is_valid());81 EXPECT_THAT(LIBC_NAMESPACE::madvise(holder.addr, holder.size, MADV_DONTNEED),82 Succeeds());83 EXPECT_THAT(LIBC_NAMESPACE::mlock2(holder.addr, holder.size, 0), Succeeds());84 unsigned char vec;85 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),86 Succeeds());87 EXPECT_EQ(vec & 1, 1);88 EXPECT_THAT(LIBC_NAMESPACE::munlock(holder.addr, holder.size), Succeeds());89 EXPECT_THAT(LIBC_NAMESPACE::madvise(holder.addr, holder.size, MADV_DONTNEED),90 Succeeds());91 EXPECT_THAT(LIBC_NAMESPACE::mlock2(holder.addr, holder.size, MLOCK_ONFAULT),92 Succeeds());93 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),94 Succeeds());95 EXPECT_EQ(vec & 1, 0);96 holder[0] = 1;97 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),98 Succeeds());99 EXPECT_EQ(vec & 1, 1);100 EXPECT_THAT(LIBC_NAMESPACE::munlock(holder.addr, holder.size), Succeeds());101}102#endif103 104TEST_F(LlvmLibcMlockTest, InvalidFlag) {105 size_t alloc_size = 128; // page size106 void *addr = LIBC_NAMESPACE::mmap(nullptr, alloc_size, PROT_READ,107 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);108 ASSERT_ERRNO_SUCCESS();109 EXPECT_NE(addr, MAP_FAILED);110 111 // Invalid mlock2 flags.112 EXPECT_THAT(LIBC_NAMESPACE::mlock2(addr, alloc_size, 1234), Fails(EINVAL));113 114 // Invalid mlockall flags.115 EXPECT_THAT(LIBC_NAMESPACE::mlockall(1234), Fails(EINVAL));116 117 // man 2 mlockall says EINVAL is a valid return code when MCL_ONFAULT was118 // specified without MCL_FUTURE or MCL_CURRENT, but this seems to fail on119 // Linux 4.19.y (EOL).120 // TODO(ndesaulniers) re-enable after121 // https://github.com/llvm/llvm-project/issues/80073 is fixed.122 // EXPECT_THAT(LIBC_NAMESPACE::mlockall(MCL_ONFAULT), Fails(EINVAL));123 124 LIBC_NAMESPACE::munmap(addr, alloc_size);125}126 127TEST_F(LlvmLibcMlockTest, MLockAll) {128 {129 PageHolder holder;130 EXPECT_TRUE(holder.is_valid());131 EXPECT_THAT(132 LIBC_NAMESPACE::madvise(holder.addr, holder.size, MADV_DONTNEED),133 Succeeds());134 auto retval = LIBC_NAMESPACE::mlockall(MCL_CURRENT);135 if (retval == -1) {136 EXPECT_TRUE(libc_errno == ENOMEM || libc_errno == EPERM);137 libc_errno = 0;138 return;139 }140 unsigned char vec;141 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),142 Succeeds());143 EXPECT_EQ(vec & 1, 1);144 EXPECT_THAT(LIBC_NAMESPACE::munlockall(), Succeeds());145 }146 {147 auto retval = LIBC_NAMESPACE::mlockall(MCL_FUTURE);148 if (retval == -1) {149 EXPECT_TRUE(libc_errno == ENOMEM || libc_errno == EPERM);150 libc_errno = 0;151 return;152 }153 PageHolder holder;154 EXPECT_TRUE(holder.is_valid());155 unsigned char vec;156 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),157 Succeeds());158 EXPECT_EQ(vec & 1, 1);159 EXPECT_THAT(LIBC_NAMESPACE::munlockall(), Succeeds());160 }161#ifdef MCL_ONFAULT162 {163 auto retval = LIBC_NAMESPACE::mlockall(MCL_FUTURE | MCL_ONFAULT);164 if (retval == -1) {165 EXPECT_TRUE(libc_errno == ENOMEM || libc_errno == EPERM);166 libc_errno = 0;167 return;168 }169 PageHolder holder;170 EXPECT_TRUE(holder.is_valid());171 unsigned char vec;172 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),173 Succeeds());174 EXPECT_EQ(vec & 1, 0);175 holder[0] = 1;176 EXPECT_THAT(LIBC_NAMESPACE::mincore(holder.addr, holder.size, &vec),177 Succeeds());178 EXPECT_EQ(vec & 1, 1);179 EXPECT_THAT(LIBC_NAMESPACE::munlockall(), Succeeds());180 }181#endif182}183