github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/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  
    23  #include "absl/strings/str_format.h"
    24  #include "absl/strings/string_view.h"
    25  #include "test/util/logging.h"
    26  #include "test/util/posix_error.h"
    27  #include "test/util/save_util.h"
    28  #include "test/util/test_util.h"
    29  
    30  namespace gvisor {
    31  namespace testing {
    32  
    33  // RAII type for mmap'ed memory. Only usable in tests due to use of a test-only
    34  // macro that can't be named without invoking the presubmit's wrath.
    35  class Mapping {
    36   public:
    37    // Constructs a mapping that owns nothing.
    38    Mapping() = default;
    39  
    40    // Constructs a mapping that owns the mmapped memory [ptr, ptr+len). Most
    41    // users should use Mmap or MmapAnon instead.
    42    Mapping(void* ptr, size_t len) : ptr_(ptr), len_(len) {}
    43  
    44    Mapping(Mapping&& orig) : ptr_(orig.ptr_), len_(orig.len_) { orig.release(); }
    45  
    46    Mapping& operator=(Mapping&& orig) {
    47      ptr_ = orig.ptr_;
    48      len_ = orig.len_;
    49      orig.release();
    50      return *this;
    51    }
    52  
    53    Mapping(Mapping const&) = delete;
    54    Mapping& operator=(Mapping const&) = delete;
    55  
    56    ~Mapping() { reset(); }
    57  
    58    void* ptr() const { return ptr_; }
    59    size_t len() const { return len_; }
    60  
    61    // Returns a pointer to the end of the mapping. Useful for when the mapping
    62    // is used as a thread stack.
    63    void* endptr() const { return reinterpret_cast<void*>(addr() + len_); }
    64  
    65    // Returns the start of this mapping cast to uintptr_t for ease of pointer
    66    // arithmetic.
    67    uintptr_t addr() const { return reinterpret_cast<uintptr_t>(ptr_); }
    68  
    69    // Returns the end of this mapping cast to uintptr_t for ease of pointer
    70    // arithmetic.
    71    uintptr_t endaddr() const { return reinterpret_cast<uintptr_t>(endptr()); }
    72  
    73    // Returns this mapping as a StringPiece for ease of comparison.
    74    //
    75    // This function is named view in anticipation of the eventual replacement of
    76    // StringPiece with std::string_view.
    77    absl::string_view view() const {
    78      return absl::string_view(static_cast<char const*>(ptr_), len_);
    79    }
    80  
    81    // These are both named reset for consistency with standard smart pointers.
    82  
    83    void reset(void* ptr, size_t len) {
    84      if (len_) {
    85        TEST_PCHECK(munmap(ptr_, len_) == 0);
    86      }
    87      ptr_ = ptr;
    88      len_ = len;
    89    }
    90  
    91    void reset() { reset(nullptr, 0); }
    92  
    93    void release() {
    94      ptr_ = nullptr;
    95      len_ = 0;
    96    }
    97  
    98   private:
    99    void* ptr_ = nullptr;
   100    size_t len_ = 0;
   101  };
   102  
   103  // Wrapper around mmap(2) that returns a Mapping.
   104  inline PosixErrorOr<Mapping> Mmap(void* addr, size_t length, int prot,
   105                                    int flags, int fd, off_t offset) {
   106    void* ptr = mmap(addr, length, prot, flags, fd, offset);
   107    if (ptr == MAP_FAILED) {
   108      return PosixError(
   109          errno, absl::StrFormat("mmap(%p, %d, %x, %x, %d, %d)", addr, length,
   110                                 prot, flags, fd, offset));
   111    }
   112    MaybeSave();
   113    return Mapping(ptr, length);
   114  }
   115  
   116  // Convenience wrapper around Mmap for anonymous mappings.
   117  inline PosixErrorOr<Mapping> MmapAnon(size_t length, int prot, int flags) {
   118    return Mmap(nullptr, length, prot, flags | MAP_ANONYMOUS, -1, 0);
   119  }
   120  
   121  // Wrapper for mremap that returns a PosixErrorOr<>, since the return type of
   122  // void* isn't directly compatible with SyscallSucceeds.
   123  inline PosixErrorOr<void*> Mremap(void* old_address, size_t old_size,
   124                                    size_t new_size, int flags,
   125                                    void* new_address) {
   126    void* rv = mremap(old_address, old_size, new_size, flags, new_address);
   127    if (rv == MAP_FAILED) {
   128      return PosixError(errno, "mremap failed");
   129    }
   130    return rv;
   131  }
   132  
   133  // Returns true if the page containing addr is mapped.
   134  inline bool IsMapped(uintptr_t addr) {
   135    int const rv = msync(reinterpret_cast<void*>(addr & ~(kPageSize - 1)),
   136                         kPageSize, MS_ASYNC);
   137    if (rv == 0) {
   138      return true;
   139    }
   140    TEST_PCHECK_MSG(errno == ENOMEM, "msync failed with unexpected errno");
   141    return false;
   142  }
   143  
   144  }  // namespace testing
   145  }  // namespace gvisor
   146  
   147  #endif  // GVISOR_TEST_UTIL_MEMORY_UTIL_H_