brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.2 KiB · 0056ccf Raw
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