File: big_buffer.h

package info (click to toggle)
chromium 135.0.7049.95-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 5,959,392 kB
  • sloc: cpp: 34,198,526; ansic: 7,100,035; javascript: 3,985,800; python: 1,395,489; asm: 896,754; xml: 722,891; pascal: 180,504; sh: 94,909; perl: 88,388; objc: 79,739; sql: 53,020; cs: 41,358; fortran: 24,137; makefile: 22,501; php: 13,699; tcl: 10,142; yacc: 8,822; ruby: 7,350; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; awk: 197; sed: 36
file content (246 lines) | stat: -rw-r--r-- 8,870 bytes parent folder | download
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_PUBLIC_CPP_BASE_BIG_BUFFER_H_
#define MOJO_PUBLIC_CPP_BASE_BIG_BUFFER_H_

#include <stdint.h>

#include <optional>
#include <utility>
#include <vector>

#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/containers/checked_iterators.h"
#include "base/containers/heap_array.h"
#include "base/containers/span.h"
#include "base/memory/raw_span.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "mojo/public/cpp/system/buffer.h"

namespace mojo_base {

class BigBuffer;
class BigBufferView;

namespace internal {

// Internal helper used by BigBuffer when backed by shared memory.
class COMPONENT_EXPORT(MOJO_BASE) BigBufferSharedMemoryRegion {
 public:
  BigBufferSharedMemoryRegion();
  BigBufferSharedMemoryRegion(mojo::ScopedSharedBufferHandle buffer_handle,
                              size_t size);
  BigBufferSharedMemoryRegion(BigBufferSharedMemoryRegion&& other);

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

  ~BigBufferSharedMemoryRegion();

  BigBufferSharedMemoryRegion& operator=(BigBufferSharedMemoryRegion&& other);

  void* memory() const { return buffer_mapping_.get(); }

  size_t size() const { return size_; }
  mojo::ScopedSharedBufferHandle TakeBufferHandle();

 private:
  friend class mojo_base::BigBuffer;
  friend class mojo_base::BigBufferView;

  size_t size_;
  mojo::ScopedSharedBufferHandle buffer_handle_;
  mojo::ScopedSharedBufferMapping buffer_mapping_;
};

}  // namespace internal

// BigBuffer represents a potentially large sequence of bytes. When passed over
// mojom (as a mojo_base::mojom::BigBuffer union), it may serialize as either an
// inlined array of bytes or as a shared buffer handle with the payload copied
// into the corresponding shared memory region. This makes it easier to send
// payloads of varying and unbounded size over IPC without fear of hitting
// message size limits.
//
// A BigBuffer may be (implicitly) constructed over any span of bytes, and it
// exposes simple |data()| and |size()| accessors akin to what common container
// types provide. Users do not need to be concerned with the actual backing
// storage used to implement this interface.
//
// SECURITY NOTE: When shmem is backing the message, it may be writable in the
// sending process while being read in the receiving process. If a BigBuffer is
// received from an untrustworthy process, you should make a copy of the data
// before processing it to avoid time-of-check time-of-use (TOCTOU) bugs.
// The |size()| of the data cannot be manipulated.
class COMPONENT_EXPORT(MOJO_BASE) BigBuffer {
 public:
  using value_type = uint8_t;
  using iterator = base::CheckedContiguousIterator<uint8_t>;
  using const_iterator = base::CheckedContiguousIterator<const uint8_t>;

  static constexpr size_t kMaxInlineBytes = 64 * 1024;

  enum class StorageType {
    kBytes,
    kSharedMemory,
    kInvalidBuffer,
  };

  // Defaults to empty kBytes storage.
  BigBuffer();

  // Constructs a BigBuffer over an existing span of bytes. Intentionally
  // implicit for convenience. Always copies the contents of |data| into some
  // internal storage.
  BigBuffer(base::span<const uint8_t> data);

  // Constructs a BigBuffer from an existing shared memory region. Not intended
  // for general-purpose use.
  explicit BigBuffer(internal::BigBufferSharedMemoryRegion shared_memory);

  // Constructs a BigBuffer with the given size. The contents of buffer memory
  // are uninitialized. Buffers constructed this way must be filled completely
  // before transfer to avoid leaking information to less privileged processes.
  explicit BigBuffer(size_t size);

  BigBuffer(BigBuffer&& other);
  BigBuffer& operator=(BigBuffer&& other);

  ~BigBuffer();

  // Returns a new BigBuffer containing a copy of this BigBuffer's contents.
  // Note that the new BigBuffer may not necessarily have the same backing
  // storage type as the original one, only the same contents.
  BigBuffer Clone() const;

  // Returns a pointer to the data stored by this BigBuffer, regardless of
  // backing storage type. Prefer to use `base::span(big_buffer)` instead, or
  // the implicit conversion to `base::span`.
  uint8_t* data() { return const_cast<uint8_t*>(std::as_const(*this).data()); }
  const uint8_t* data() const;

  // Returns the size of the data stored by this BigBuffer, regardless of
  // backing storage type.
  size_t size() const;

  StorageType storage_type() const { return storage_type_; }

  // WARNING: This method does not work for buffers backed by shared memory. To
  // get a span independent of the storage type, write `base::span(big_buffer)`,
  // or rely on the implicit conversion.
  base::span<const uint8_t> byte_span() const {
    CHECK_EQ(storage_type_, StorageType::kBytes);
    return bytes_.as_span();
  }

  internal::BigBufferSharedMemoryRegion& shared_memory() {
    CHECK_EQ(storage_type_, StorageType::kSharedMemory);
    return shared_memory_.value();
  }

  iterator begin() {
    uint8_t* const ptr = data();
    // SAFETY: If this is an invalid buffer, `ptr` is null and `size()` is zero,
    // which results in a well-defined (null) result. Otherwise, the underlying
    // storage (`bytes_` or `shared_memory_`) guarantees that `ptr` points to at
    // least `size()` bytes.
    return UNSAFE_BUFFERS(iterator(ptr, ptr + size()));
  }

  const_iterator begin() const {
    const uint8_t* const ptr = data();
    // SAFETY: As in the non-const version above.
    return UNSAFE_BUFFERS(const_iterator(ptr, ptr + size()));
  }

  const_iterator cbegin() const { return begin(); }

  iterator end() {
    uint8_t* const ptr = data();
    const size_t len = size();
    // SAFETY: As in `begin()` above.
    return UNSAFE_BUFFERS(iterator(ptr, ptr + len, ptr + len));
  }

  const_iterator end() const {
    const uint8_t* const ptr = data();
    const size_t len = size();
    // SAFETY: As in the non-const version above.
    return UNSAFE_BUFFERS(const_iterator(ptr, ptr + len, ptr + len));
  }

  const_iterator cend() const { return end(); }

 private:
  friend class BigBufferView;

  StorageType storage_type_ = StorageType::kBytes;
  base::HeapArray<uint8_t> bytes_;
  std::optional<internal::BigBufferSharedMemoryRegion> shared_memory_;
};

// Similar to BigBuffer, but doesn't *necessarily* own the buffer storage.
// Namely, if constructed over a small enough span of memory, it will simply
// retain a reference to that memory. This is generally only safe to use for
// serialization and deserialization.
class COMPONENT_EXPORT(MOJO_BASE) BigBufferView {
 public:
  BigBufferView();
  BigBufferView(BigBufferView&& other);

  // Constructs a BigBufferView over |bytes|. If |bytes| is large enough, this
  // will allocate shared memory and copy the contents there. Otherwise this
  // will retain an unsafe reference to |bytes| and must therefore not outlive
  // |bytes|.
  explicit BigBufferView(base::span<const uint8_t> bytes);

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

  ~BigBufferView();

  BigBufferView& operator=(BigBufferView&& other);

  base::span<const uint8_t> data() const;

  // Explicitly retains a reference to |bytes| as the backing storage for this
  // view. Does not copy and therefore |bytes| must remain valid throughout the
  // view's lifetime. Used for deserialization.
  void SetBytes(base::span<const uint8_t> bytes);

  // Explictly adopts |shared_memory| as the backing storage for this view. Used
  // for deserialization.
  void SetSharedMemory(internal::BigBufferSharedMemoryRegion shared_memory);

  // Converts to a BigBuffer which owns the viewed data. May have to copy data.
  [[nodiscard]] static BigBuffer ToBigBuffer(BigBufferView view);

  BigBuffer::StorageType storage_type() const { return storage_type_; }

  // WARNING: This method does not work for buffers backed by shared memory. To
  // get a span independent of the storage type, use `data()`.
  base::span<const uint8_t> bytes() const {
    DCHECK_EQ(storage_type_, BigBuffer::StorageType::kBytes);
    return bytes_;
  }

  internal::BigBufferSharedMemoryRegion& shared_memory() {
    DCHECK_EQ(storage_type_, BigBuffer::StorageType::kSharedMemory);
    return shared_memory_.value();
  }

  static BigBufferView CreateInvalidForTest();

 private:
  BigBuffer::StorageType storage_type_ = BigBuffer::StorageType::kBytes;
  base::raw_span<const uint8_t> bytes_;
  std::optional<internal::BigBufferSharedMemoryRegion> shared_memory_;
};

}  // namespace mojo_base

#endif  // MOJO_PUBLIC_CPP_BASE_BIG_BUFFER_H_