mirror of
https://github.com/klzgrad/naiveproxy.git
synced 2024-11-28 08:16:09 +03:00
250 lines
9.0 KiB
C
250 lines
9.0 KiB
C
|
// 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 BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
|
||
|
#define BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
|
||
|
|
||
|
#include <cstddef>
|
||
|
#include <type_traits>
|
||
|
|
||
|
#include "base/base_export.h"
|
||
|
#include "base/check.h"
|
||
|
#include "base/containers/span.h"
|
||
|
#include "base/memory/raw_ptr.h"
|
||
|
#include "base/memory/shared_memory_mapper.h"
|
||
|
#include "base/unguessable_token.h"
|
||
|
|
||
|
namespace base {
|
||
|
|
||
|
namespace subtle {
|
||
|
class PlatformSharedMemoryRegion;
|
||
|
} // namespace subtle
|
||
|
|
||
|
// Base class for scoped handles to a shared memory mapping created from a
|
||
|
// shared memory region. Created shared memory mappings remain valid even if the
|
||
|
// creator region is transferred or destroyed.
|
||
|
//
|
||
|
// Each mapping has an UnguessableToken that identifies the shared memory region
|
||
|
// it was created from. This is used for memory metrics, to avoid overcounting
|
||
|
// shared memory.
|
||
|
class BASE_EXPORT SharedMemoryMapping {
|
||
|
public:
|
||
|
// Default constructor initializes an invalid instance.
|
||
|
SharedMemoryMapping();
|
||
|
|
||
|
// Move operations are allowed.
|
||
|
SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept;
|
||
|
SharedMemoryMapping& operator=(SharedMemoryMapping&& mapping) noexcept;
|
||
|
|
||
|
SharedMemoryMapping(const SharedMemoryMapping&) = delete;
|
||
|
SharedMemoryMapping& operator=(const SharedMemoryMapping&) = delete;
|
||
|
|
||
|
// Unmaps the region if the mapping is valid.
|
||
|
virtual ~SharedMemoryMapping();
|
||
|
|
||
|
// Returns true iff the mapping is valid. False means there is no
|
||
|
// corresponding area of memory.
|
||
|
bool IsValid() const { return !mapped_span_.empty(); }
|
||
|
|
||
|
// Returns the logical size of the mapping in bytes. This is precisely the
|
||
|
// size requested by whoever created the mapping, and it is always less than
|
||
|
// or equal to |mapped_size()|. This is undefined for invalid instances.
|
||
|
size_t size() const {
|
||
|
DCHECK(IsValid());
|
||
|
return size_;
|
||
|
}
|
||
|
|
||
|
// Returns the actual size of the mapping in bytes. This is always at least
|
||
|
// as large as |size()| but may be larger due to platform mapping alignment
|
||
|
// constraints. This is undefined for invalid instances.
|
||
|
size_t mapped_size() const {
|
||
|
DCHECK(IsValid());
|
||
|
return mapped_span_.size();
|
||
|
}
|
||
|
|
||
|
// Returns 128-bit GUID of the region this mapping belongs to.
|
||
|
const UnguessableToken& guid() const {
|
||
|
DCHECK(IsValid());
|
||
|
return guid_;
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
SharedMemoryMapping(span<uint8_t> mapped_span,
|
||
|
size_t size,
|
||
|
const UnguessableToken& guid,
|
||
|
SharedMemoryMapper* mapper);
|
||
|
void* raw_memory_ptr() const {
|
||
|
return reinterpret_cast<void*>(mapped_span_.data());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
friend class SharedMemoryTracker;
|
||
|
|
||
|
void Unmap();
|
||
|
|
||
|
span<uint8_t> mapped_span_;
|
||
|
size_t size_ = 0;
|
||
|
UnguessableToken guid_;
|
||
|
raw_ptr<SharedMemoryMapper> mapper_ = nullptr;
|
||
|
};
|
||
|
|
||
|
// Class modeling a read-only mapping of a shared memory region into the
|
||
|
// current process' address space. This is created by ReadOnlySharedMemoryRegion
|
||
|
// instances.
|
||
|
class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
|
||
|
public:
|
||
|
// Default constructor initializes an invalid instance.
|
||
|
ReadOnlySharedMemoryMapping();
|
||
|
|
||
|
ReadOnlySharedMemoryMapping(const ReadOnlySharedMemoryMapping&) = delete;
|
||
|
ReadOnlySharedMemoryMapping& operator=(const ReadOnlySharedMemoryMapping&) =
|
||
|
delete;
|
||
|
|
||
|
// Move operations are allowed.
|
||
|
ReadOnlySharedMemoryMapping(ReadOnlySharedMemoryMapping&&) noexcept;
|
||
|
ReadOnlySharedMemoryMapping& operator=(
|
||
|
ReadOnlySharedMemoryMapping&&) noexcept;
|
||
|
|
||
|
// Returns the base address of the read-only mapping. Returns nullptr for
|
||
|
// invalid instances.
|
||
|
const void* memory() const { return raw_memory_ptr(); }
|
||
|
|
||
|
// Returns a pointer to a page-aligned const T if the mapping is valid and
|
||
|
// large enough to contain a T, or nullptr otherwise.
|
||
|
template <typename T>
|
||
|
const T* GetMemoryAs() const {
|
||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||
|
"Copying non-trivially-copyable object across memory spaces "
|
||
|
"is dangerous");
|
||
|
if (!IsValid())
|
||
|
return nullptr;
|
||
|
if (sizeof(T) > size())
|
||
|
return nullptr;
|
||
|
return static_cast<const T*>(raw_memory_ptr());
|
||
|
}
|
||
|
|
||
|
// Returns a span of const T. The number of elements is autodeduced from the
|
||
|
// size of the shared memory mapping. The number of elements may be
|
||
|
// autodeduced as zero, i.e. the mapping is invalid or the size of the mapping
|
||
|
// isn't large enough to contain even one T: in that case, an empty span
|
||
|
// will be returned. The first element, if any, is guaranteed to be
|
||
|
// page-aligned.
|
||
|
template <typename T>
|
||
|
span<const T> GetMemoryAsSpan() const {
|
||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||
|
"Copying non-trivially-copyable object across memory spaces "
|
||
|
"is dangerous");
|
||
|
if (!IsValid())
|
||
|
return span<const T>();
|
||
|
size_t count = size() / sizeof(T);
|
||
|
return GetMemoryAsSpan<T>(count);
|
||
|
}
|
||
|
|
||
|
// Returns a span of const T with |count| elements if the mapping is valid and
|
||
|
// large enough to contain |count| elements, or an empty span otherwise. The
|
||
|
// first element, if any, is guaranteed to be page-aligned.
|
||
|
template <typename T>
|
||
|
span<const T> GetMemoryAsSpan(size_t count) const {
|
||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||
|
"Copying non-trivially-copyable object across memory spaces "
|
||
|
"is dangerous");
|
||
|
if (!IsValid())
|
||
|
return span<const T>();
|
||
|
if (size() / sizeof(T) < count)
|
||
|
return span<const T>();
|
||
|
return span<const T>(static_cast<const T*>(raw_memory_ptr()), count);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
friend class ReadOnlySharedMemoryRegion;
|
||
|
ReadOnlySharedMemoryMapping(span<uint8_t> mapped_span,
|
||
|
size_t size,
|
||
|
const UnguessableToken& guid,
|
||
|
SharedMemoryMapper* mapper);
|
||
|
};
|
||
|
|
||
|
// Class modeling a writable mapping of a shared memory region into the
|
||
|
// current process' address space. This is created by *SharedMemoryRegion
|
||
|
// instances.
|
||
|
class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
|
||
|
public:
|
||
|
// Default constructor initializes an invalid instance.
|
||
|
WritableSharedMemoryMapping();
|
||
|
|
||
|
WritableSharedMemoryMapping(const WritableSharedMemoryMapping&) = delete;
|
||
|
WritableSharedMemoryMapping& operator=(const WritableSharedMemoryMapping&) =
|
||
|
delete;
|
||
|
|
||
|
// Move operations are allowed.
|
||
|
WritableSharedMemoryMapping(WritableSharedMemoryMapping&&) noexcept;
|
||
|
WritableSharedMemoryMapping& operator=(
|
||
|
WritableSharedMemoryMapping&&) noexcept;
|
||
|
|
||
|
// Returns the base address of the writable mapping. Returns nullptr for
|
||
|
// invalid instances.
|
||
|
void* memory() const { return raw_memory_ptr(); }
|
||
|
|
||
|
// Returns a pointer to a page-aligned T if the mapping is valid and large
|
||
|
// enough to contain a T, or nullptr otherwise.
|
||
|
template <typename T>
|
||
|
T* GetMemoryAs() const {
|
||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||
|
"Copying non-trivially-copyable object across memory spaces "
|
||
|
"is dangerous");
|
||
|
if (!IsValid())
|
||
|
return nullptr;
|
||
|
if (sizeof(T) > size())
|
||
|
return nullptr;
|
||
|
return static_cast<T*>(raw_memory_ptr());
|
||
|
}
|
||
|
|
||
|
// Returns a span of T. The number of elements is autodeduced from the size of
|
||
|
// the shared memory mapping. The number of elements may be autodeduced as
|
||
|
// zero, i.e. the mapping is invalid or the size of the mapping isn't large
|
||
|
// enough to contain even one T: in that case, an empty span will be returned.
|
||
|
// The first element, if any, is guaranteed to be page-aligned.
|
||
|
template <typename T>
|
||
|
span<T> GetMemoryAsSpan() const {
|
||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||
|
"Copying non-trivially-copyable object across memory spaces "
|
||
|
"is dangerous");
|
||
|
if (!IsValid())
|
||
|
return span<T>();
|
||
|
size_t count = size() / sizeof(T);
|
||
|
return GetMemoryAsSpan<T>(count);
|
||
|
}
|
||
|
|
||
|
// Returns a span of T with |count| elements if the mapping is valid and large
|
||
|
// enough to contain |count| elements, or an empty span otherwise. The first
|
||
|
// element, if any, is guaranteed to be page-aligned.
|
||
|
template <typename T>
|
||
|
span<T> GetMemoryAsSpan(size_t count) const {
|
||
|
static_assert(std::is_trivially_copyable<T>::value,
|
||
|
"Copying non-trivially-copyable object across memory spaces "
|
||
|
"is dangerous");
|
||
|
if (!IsValid())
|
||
|
return span<T>();
|
||
|
if (size() / sizeof(T) < count)
|
||
|
return span<T>();
|
||
|
return span<T>(static_cast<T*>(raw_memory_ptr()), count);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
friend WritableSharedMemoryMapping MapAtForTesting(
|
||
|
subtle::PlatformSharedMemoryRegion* region,
|
||
|
uint64_t offset,
|
||
|
size_t size);
|
||
|
friend class ReadOnlySharedMemoryRegion;
|
||
|
friend class WritableSharedMemoryRegion;
|
||
|
friend class UnsafeSharedMemoryRegion;
|
||
|
WritableSharedMemoryMapping(span<uint8_t> mapped_span,
|
||
|
size_t size,
|
||
|
const UnguessableToken& guid,
|
||
|
SharedMemoryMapper* mapper);
|
||
|
};
|
||
|
|
||
|
} // namespace base
|
||
|
|
||
|
#endif // BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
|