Commit fcdae7e0 authored by Daniel Cheng's avatar Daniel Cheng Committed by Commit Bot

Add type-safer helpers for accessing SharedMemoryMappings.

- GetMemoryAs<T> should be used when the mapping contains one T.
- GetMemoryAsSpan<T> should be used when the mapping contains more than
  one T. The element count can be explicitly specified or autodeduced
  from the size of the shared memory mapping.

Bug: 795291, 866975
Change-Id: Icea4e276a26a1c47688c0a5206b97cd42ff92043
Reviewed-on: https://chromium-review.googlesource.com/1144312Reviewed-by: default avatardanakj <danakj@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarAlexandr Ilin <alexilin@chromium.org>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577630}
parent b75efb08
...@@ -2296,6 +2296,7 @@ test("base_unittests") { ...@@ -2296,6 +2296,7 @@ test("base_unittests") {
"memory/ref_counted_memory_unittest.cc", "memory/ref_counted_memory_unittest.cc",
"memory/ref_counted_unittest.cc", "memory/ref_counted_unittest.cc",
"memory/shared_memory_mac_unittest.cc", "memory/shared_memory_mac_unittest.cc",
"memory/shared_memory_mapping_unittest.cc",
"memory/shared_memory_region_unittest.cc", "memory/shared_memory_region_unittest.cc",
"memory/shared_memory_unittest.cc", "memory/shared_memory_unittest.cc",
"memory/shared_memory_win_unittest.cc", "memory/shared_memory_win_unittest.cc",
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <cstddef> #include <cstddef>
#include "base/containers/span.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
...@@ -97,6 +98,43 @@ class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping { ...@@ -97,6 +98,43 @@ class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
// page-aligned. This is nullptr for invalid instances. // page-aligned. This is nullptr for invalid instances.
const void* memory() const { return raw_memory_ptr(); } 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 {
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 {
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 {
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: private:
friend class ReadOnlySharedMemoryRegion; friend class ReadOnlySharedMemoryRegion;
ReadOnlySharedMemoryMapping(void* address, ReadOnlySharedMemoryMapping(void* address,
...@@ -123,6 +161,42 @@ class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping { ...@@ -123,6 +161,42 @@ class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
// page-aligned. This is nullptr for invalid instances. // page-aligned. This is nullptr for invalid instances.
void* memory() const { return raw_memory_ptr(); } 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 {
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 {
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 {
if (!IsValid())
return span<T>();
if (size() / sizeof(T) < count)
return span<T>();
return span<T>(static_cast<T*>(raw_memory_ptr()), count);
}
private: private:
friend WritableSharedMemoryMapping MapAtForTesting( friend WritableSharedMemoryMapping MapAtForTesting(
subtle::PlatformSharedMemoryRegion* region, subtle::PlatformSharedMemoryRegion* region,
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/shared_memory_mapping.h"
#include <stdint.h>
#include <algorithm>
#include <limits>
#include "base/containers/span.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
class SharedMemoryMappingTest : public ::testing::Test {
protected:
void CreateMapping(size_t size) {
auto result = ReadOnlySharedMemoryRegion::Create(size);
ASSERT_TRUE(result.IsValid());
write_mapping_ = std::move(result.mapping);
read_mapping_ = result.region.Map();
ASSERT_TRUE(read_mapping_.IsValid());
}
WritableSharedMemoryMapping write_mapping_;
ReadOnlySharedMemoryMapping read_mapping_;
};
TEST_F(SharedMemoryMappingTest, Invalid) {
EXPECT_EQ(nullptr, write_mapping_.GetMemoryAs<uint8_t>());
EXPECT_EQ(nullptr, read_mapping_.GetMemoryAs<uint8_t>());
EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint8_t>().empty());
EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>().empty());
EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint8_t>(1).empty());
EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>(1).empty());
}
TEST_F(SharedMemoryMappingTest, Scalar) {
CreateMapping(sizeof(uint32_t));
uint32_t* write_ptr = write_mapping_.GetMemoryAs<uint32_t>();
EXPECT_NE(nullptr, write_ptr);
const uint32_t* read_ptr = read_mapping_.GetMemoryAs<uint32_t>();
EXPECT_NE(nullptr, read_ptr);
*write_ptr = 0u;
EXPECT_EQ(0u, *read_ptr);
*write_ptr = 0x12345678u;
EXPECT_EQ(0x12345678u, *read_ptr);
}
TEST_F(SharedMemoryMappingTest, SpanWithAutoDeducedElementCount) {
CreateMapping(sizeof(uint8_t) * 8);
span<uint8_t> write_span = write_mapping_.GetMemoryAsSpan<uint8_t>();
ASSERT_EQ(8u, write_span.size());
span<const uint32_t> read_span = read_mapping_.GetMemoryAsSpan<uint32_t>();
ASSERT_EQ(2u, read_span.size());
std::fill(write_span.begin(), write_span.end(), 0);
EXPECT_EQ(0u, read_span[0]);
EXPECT_EQ(0u, read_span[1]);
for (size_t i = 0; i < write_span.size(); ++i)
write_span[i] = i + 1;
EXPECT_EQ(0x04030201u, read_span[0]);
EXPECT_EQ(0x08070605u, read_span[1]);
}
TEST_F(SharedMemoryMappingTest, SpanWithExplicitElementCount) {
CreateMapping(sizeof(uint8_t) * 8);
span<uint8_t> write_span = write_mapping_.GetMemoryAsSpan<uint8_t>(8);
ASSERT_EQ(8u, write_span.size());
span<uint8_t> write_span_2 = write_mapping_.GetMemoryAsSpan<uint8_t>(4);
ASSERT_EQ(4u, write_span_2.size());
span<const uint32_t> read_span = read_mapping_.GetMemoryAsSpan<uint32_t>(2);
ASSERT_EQ(2u, read_span.size());
span<const uint32_t> read_span_2 = read_mapping_.GetMemoryAsSpan<uint32_t>(1);
ASSERT_EQ(1u, read_span_2.size());
std::fill(write_span.begin(), write_span.end(), 0);
EXPECT_EQ(0u, read_span[0]);
EXPECT_EQ(0u, read_span[1]);
EXPECT_EQ(0u, read_span_2[0]);
for (size_t i = 0; i < write_span.size(); ++i)
write_span[i] = i + 1;
EXPECT_EQ(0x04030201u, read_span[0]);
EXPECT_EQ(0x08070605u, read_span[1]);
EXPECT_EQ(0x04030201u, read_span_2[0]);
std::fill(write_span_2.begin(), write_span_2.end(), 0);
EXPECT_EQ(0u, read_span[0]);
EXPECT_EQ(0x08070605u, read_span[1]);
EXPECT_EQ(0u, read_span_2[0]);
}
TEST_F(SharedMemoryMappingTest, SpanWithZeroElementCount) {
CreateMapping(sizeof(uint8_t) * 8);
EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint8_t>(0).empty());
EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint8_t>(0).empty());
}
TEST_F(SharedMemoryMappingTest, TooBigScalar) {
CreateMapping(sizeof(uint8_t));
EXPECT_EQ(nullptr, write_mapping_.GetMemoryAs<uint32_t>());
EXPECT_EQ(nullptr, read_mapping_.GetMemoryAs<uint32_t>());
}
TEST_F(SharedMemoryMappingTest, TooBigSpanWithAutoDeducedElementCount) {
CreateMapping(sizeof(uint8_t));
EXPECT_TRUE(write_mapping_.GetMemoryAsSpan<uint32_t>().empty());
EXPECT_TRUE(read_mapping_.GetMemoryAsSpan<uint32_t>().empty());
}
TEST_F(SharedMemoryMappingTest, TooBigSpanWithExplicitElementCount) {
CreateMapping(sizeof(uint8_t));
// Deliberately pick element counts such that a naive bounds calculation would
// overflow.
EXPECT_TRUE(write_mapping_
.GetMemoryAsSpan<uint32_t>(std::numeric_limits<size_t>::max())
.empty());
EXPECT_TRUE(read_mapping_
.GetMemoryAsSpan<uint32_t>(std::numeric_limits<size_t>::max())
.empty());
}
} // namespace base
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment