summaryrefslogtreecommitdiffhomepage
path: root/test/util/memory_util.h
blob: 8f6e99ba649103777fae7b8a7e0816070f6a9381 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef GVISOR_TEST_UTIL_MEMORY_UTIL_H_
#define GVISOR_TEST_UTIL_MEMORY_UTIL_H_

#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>

#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "test/util/logging.h"
#include "test/util/posix_error.h"
#include "test/util/save_util.h"
#include "test/util/test_util.h"

namespace gvisor {
namespace testing {

// RAII type for mmap'ed memory. Only usable in tests due to use of a test-only
// macro that can't be named without invoking the presubmit's wrath.
class Mapping {
 public:
  // Constructs a mapping that owns nothing.
  Mapping() = default;

  // Constructs a mapping that owns the mmapped memory [ptr, ptr+len). Most
  // users should use Mmap or MmapAnon instead.
  Mapping(void* ptr, size_t len) : ptr_(ptr), len_(len) {}

  Mapping(Mapping&& orig) : ptr_(orig.ptr_), len_(orig.len_) { orig.release(); }

  Mapping& operator=(Mapping&& orig) {
    ptr_ = orig.ptr_;
    len_ = orig.len_;
    orig.release();
    return *this;
  }

  Mapping(Mapping const&) = delete;
  Mapping& operator=(Mapping const&) = delete;

  ~Mapping() { reset(); }

  void* ptr() const { return ptr_; }
  size_t len() const { return len_; }

  // Returns a pointer to the end of the mapping. Useful for when the mapping
  // is used as a thread stack.
  void* endptr() const { return reinterpret_cast<void*>(addr() + len_); }

  // Returns the start of this mapping cast to uintptr_t for ease of pointer
  // arithmetic.
  uintptr_t addr() const { return reinterpret_cast<uintptr_t>(ptr_); }

  // Returns the end of this mapping cast to uintptr_t for ease of pointer
  // arithmetic.
  uintptr_t endaddr() const { return reinterpret_cast<uintptr_t>(endptr()); }

  // Returns this mapping as a StringPiece for ease of comparison.
  //
  // This function is named view in anticipation of the eventual replacement of
  // StringPiece with std::string_view.
  absl::string_view view() const {
    return absl::string_view(static_cast<char const*>(ptr_), len_);
  }

  // These are both named reset for consistency with standard smart pointers.

  void reset(void* ptr, size_t len) {
    if (len_) {
      TEST_PCHECK(munmap(ptr_, len_) == 0);
    }
    ptr_ = ptr;
    len_ = len;
  }

  void reset() { reset(nullptr, 0); }

  void release() {
    ptr_ = nullptr;
    len_ = 0;
  }

 private:
  void* ptr_ = nullptr;
  size_t len_ = 0;
};

// Wrapper around mmap(2) that returns a Mapping.
inline PosixErrorOr<Mapping> Mmap(void* addr, size_t length, int prot,
                                  int flags, int fd, off_t offset) {
  void* ptr = mmap(addr, length, prot, flags, fd, offset);
  if (ptr == MAP_FAILED) {
    return PosixError(
        errno, absl::StrFormat("mmap(%p, %d, %x, %x, %d, %d)", addr, length,
                               prot, flags, fd, offset));
  }
  MaybeSave();
  return Mapping(ptr, length);
}

// Convenience wrapper around Mmap for anonymous mappings.
inline PosixErrorOr<Mapping> MmapAnon(size_t length, int prot, int flags) {
  return Mmap(nullptr, length, prot, flags | MAP_ANONYMOUS, -1, 0);
}

}  // namespace testing
}  // namespace gvisor

#endif  // GVISOR_TEST_UTIL_MEMORY_UTIL_H_