gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/util/memory_util.h (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #ifndef GVISOR_TEST_UTIL_MEMORY_UTIL_H_
    16  #define GVISOR_TEST_UTIL_MEMORY_UTIL_H_
    17  
    18  #include <errno.h>
    19  #include <stddef.h>
    20  #include <stdint.h>
    21  #include <sys/mman.h>
    22  #include <sys/syscall.h>
    23  #include <unistd.h>
    24  
    25  #include "absl/strings/str_format.h"
    26  #include "absl/strings/string_view.h"
    27  #include "test/util/logging.h"
    28  #include "test/util/posix_error.h"
    29  #include "test/util/save_util.h"
    30  #include "test/util/test_util.h"
    31  
    32  namespace gvisor {
    33  namespace testing {
    34  
    35  // Async-signal-safe version of munmap(2).
    36  inline int MunmapSafe(void* addr, size_t length) {
    37    return syscall(SYS_munmap, addr, length);
    38  }
    39  
    40  // RAII type for mmap'ed memory. Only usable in tests due to use of a test-only
    41  // macro that can't be named without invoking the presubmit's wrath.
    42  class Mapping {
    43   public:
    44    // Constructs a mapping that owns nothing.
    45    Mapping() = default;
    46  
    47    // Constructs a mapping that owns the mmapped memory [ptr, ptr+len). Most
    48    // users should use Mmap or MmapAnon instead.
    49    Mapping(void* ptr, size_t len) : ptr_(ptr), len_(len) {}
    50  
    51    Mapping(Mapping&& orig) : ptr_(orig.ptr_), len_(orig.len_) { orig.release(); }
    52  
    53    Mapping& operator=(Mapping&& orig) {
    54      ptr_ = orig.ptr_;
    55      len_ = orig.len_;
    56      orig.release();
    57      return *this;
    58    }
    59  
    60    Mapping(Mapping const&) = delete;
    61    Mapping& operator=(Mapping const&) = delete;
    62  
    63    ~Mapping() { reset(); }
    64  
    65    void* ptr() const { return ptr_; }
    66    size_t len() const { return len_; }
    67  
    68    // Returns a pointer to the end of the mapping. Useful for when the mapping
    69    // is used as a thread stack.
    70    void* endptr() const { return reinterpret_cast<void*>(addr() + len_); }
    71  
    72    // Returns the start of this mapping cast to uintptr_t for ease of pointer
    73    // arithmetic.
    74    uintptr_t addr() const { return reinterpret_cast<uintptr_t>(ptr_); }
    75  
    76    // Returns the end of this mapping cast to uintptr_t for ease of pointer
    77    // arithmetic.
    78    uintptr_t endaddr() const { return reinterpret_cast<uintptr_t>(endptr()); }
    79  
    80    // Returns this mapping as a StringPiece for ease of comparison.
    81    //
    82    // This function is named view in anticipation of the eventual replacement of
    83    // StringPiece with std::string_view.
    84    absl::string_view view() const {
    85      return absl::string_view(static_cast<char const*>(ptr_), len_);
    86    }
    87  
    88    // These are both named reset for consistency with standard smart pointers.
    89  
    90    void reset(void* ptr, size_t len) {
    91      if (len_) {
    92        TEST_PCHECK(MunmapSafe(ptr_, len_) == 0);
    93      }
    94      ptr_ = ptr;
    95      len_ = len;
    96    }
    97  
    98    void reset() { reset(nullptr, 0); }
    99  
   100    void release() {
   101      ptr_ = nullptr;
   102      len_ = 0;
   103    }
   104  
   105   private:
   106    void* ptr_ = nullptr;
   107    size_t len_ = 0;
   108  };
   109  
   110  // Wrapper around mmap(2) that returns a Mapping.
   111  inline PosixErrorOr<Mapping> Mmap(void* addr, size_t length, int prot,
   112                                    int flags, int fd, off_t offset) {
   113    void* ptr = mmap(addr, length, prot, flags, fd, offset);
   114    if (ptr == MAP_FAILED) {
   115      return PosixError(
   116          errno, absl::StrFormat("mmap(%p, %d, %x, %x, %d, %d)", addr, length,
   117                                 prot, flags, fd, offset));
   118    }
   119    MaybeSave();
   120    return Mapping(ptr, length);
   121  }
   122  
   123  // Convenience wrapper around Mmap for anonymous mappings.
   124  inline PosixErrorOr<Mapping> MmapAnon(size_t length, int prot, int flags) {
   125    return Mmap(nullptr, length, prot, flags | MAP_ANONYMOUS, -1, 0);
   126  }
   127  
   128  // Wrapper for mremap that returns a PosixErrorOr<>, since the return type of
   129  // void* isn't directly compatible with SyscallSucceeds.
   130  inline PosixErrorOr<void*> Mremap(void* old_address, size_t old_size,
   131                                    size_t new_size, int flags,
   132                                    void* new_address) {
   133    void* rv = mremap(old_address, old_size, new_size, flags, new_address);
   134    if (rv == MAP_FAILED) {
   135      return PosixError(errno, "mremap failed");
   136    }
   137    return rv;
   138  }
   139  
   140  // Returns true if the page containing addr is mapped.
   141  inline bool IsMapped(uintptr_t addr) {
   142    int const rv = msync(reinterpret_cast<void*>(addr & ~(kPageSize - 1)),
   143                         kPageSize, MS_ASYNC);
   144    if (rv == 0) {
   145      return true;
   146    }
   147    TEST_PCHECK_MSG(errno == ENOMEM, "msync failed with unexpected errno");
   148    return false;
   149  }
   150  
   151  }  // namespace testing
   152  }  // namespace gvisor
   153  
   154  #endif  // GVISOR_TEST_UTIL_MEMORY_UTIL_H_