普通文本  |  295行  |  9.79 KB

// Copyright 2014 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 "mojo/system/memory.h"

#include <stddef.h>
#include <stdint.h>

#include <limits>

#include "mojo/public/c/system/macros.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace system {
namespace {

TEST(MemoryTest, Valid) {
  char my_char;
  int32_t my_int32;
  int64_t my_int64_array[5] = {};  // Zero initialize.

  UserPointer<char> my_char_ptr(&my_char);
  UserPointer<int32_t> my_int32_ptr(&my_int32);
  UserPointer<int64_t> my_int64_array_ptr(my_int64_array);

  // |UserPointer<>::IsNull()|:
  EXPECT_FALSE(my_char_ptr.IsNull());
  EXPECT_FALSE(my_int32_ptr.IsNull());
  EXPECT_FALSE(my_int64_array_ptr.IsNull());

  // |UserPointer<>::Put()| and |UserPointer<>::Get()|:
  my_char_ptr.Put('x');
  EXPECT_EQ('x', my_char);
  EXPECT_EQ('x', my_char_ptr.Get());
  my_int32_ptr.Put(123);
  EXPECT_EQ(123, my_int32);
  EXPECT_EQ(123, my_int32_ptr.Get());
  my_int64_array_ptr.Put(456);
  EXPECT_EQ(456, my_int64_array[0]);
  EXPECT_EQ(456, my_int64_array_ptr.Get());

  // |UserPointer<>::At()|, etc.:
  my_int64_array_ptr.At(3).Put(789);
  EXPECT_EQ(789, my_int64_array[3]);
  {
    // Copy construction:
    UserPointer<int64_t> other(my_int64_array_ptr.At(3));
    EXPECT_FALSE(other.IsNull());
    EXPECT_EQ(789, other.Get());

    // Assignment:
    other = my_int64_array_ptr;
    EXPECT_FALSE(other.IsNull());
    EXPECT_EQ(456, other.Get());

    // Assignment to |NullUserPointer()|:
    other = NullUserPointer();
    EXPECT_TRUE(other.IsNull());

    // |MakeUserPointer()|:
    other = MakeUserPointer(&my_int64_array[1]);
    other.Put(-123);
    EXPECT_EQ(-123, my_int64_array_ptr.At(1).Get());
  }

  // "const" |UserPointer<>|:
  {
    // Explicit constructor from |NullUserPointer()|:
    UserPointer<const char> other((NullUserPointer()));
    EXPECT_TRUE(other.IsNull());

    // Conversion to "const":
    other = my_char_ptr;
    EXPECT_EQ('x', other.Get());
  }

  // Default constructor:
  {
    UserPointer<int32_t> other;
    EXPECT_TRUE(other.IsNull());

    other = my_int32_ptr;
    other.Put(-456);
    EXPECT_EQ(-456, my_int32_ptr.Get());
  }

  // |UserPointer<>::CheckArray()|:
  my_int64_array_ptr.CheckArray(5);

  // |UserPointer<>::GetArray()|:
  {
    // From a "const" |UserPointer<>| (why not?):
    UserPointer<const int64_t> other(my_int64_array_ptr);
    int64_t array[3] = {1, 2, 3};
    other.At(1).GetArray(array, 3);
    EXPECT_EQ(-123, array[0]);
    EXPECT_EQ(0, array[1]);
    EXPECT_EQ(789, array[2]);
  }

  // |UserPointer<>::PutArray()|:
  {
    const int64_t array[2] = {654, 321};
    my_int64_array_ptr.At(3).PutArray(array, 2);
    EXPECT_EQ(0, my_int64_array[2]);
    EXPECT_EQ(654, my_int64_array[3]);
    EXPECT_EQ(321, my_int64_array[4]);
  }

  // |UserPointer<>::Reader|:
  {
    UserPointer<int64_t>::Reader reader(my_int64_array_ptr, 5);
    EXPECT_EQ(456, reader.GetPointer()[0]);
    EXPECT_EQ(321, reader.GetPointer()[4]);
  }

  // Non-const to const:
  {
    UserPointer<const int64_t>::Reader reader(my_int64_array_ptr.At(3), 1);
    const int64_t* ptr = reader.GetPointer();
    EXPECT_EQ(654, *ptr);
  }

  // |UserPointer<>::Writer|:
  {
    UserPointer<int64_t>::Writer writer(my_int64_array_ptr.At(2), 1);
    int64_t* ptr = writer.GetPointer();
    *ptr = 1234567890123LL;
    writer.Commit();
    EXPECT_EQ(1234567890123LL, my_int64_array[2]);
  }

  // |UserPointer<>::ReaderWriter|:
  {
    UserPointer<int32_t>::ReaderWriter reader_writer(my_int32_ptr, 1);
    int32_t* ptr = reader_writer.GetPointer();
    EXPECT_EQ(-456, *ptr);
    *ptr = 42;
    reader_writer.Commit();
    EXPECT_EQ(42, my_int32);
  }

  // |UserPointer<>::ReinterpretCast<>|:
  // (This assumes little-endian, etc.)
  {
    UserPointer<const char> other(my_int32_ptr.ReinterpretCast<char>());
    EXPECT_EQ(42, other.Get());
    EXPECT_EQ(0, other.At(1).Get());
    EXPECT_EQ(0, other.At(2).Get());
    EXPECT_EQ(0, other.At(3).Get());
  }

  // |UserPointer<>::GetPointerValue()|:
  {
    UserPointer<int32_t> other;
    EXPECT_EQ(0u, other.GetPointerValue());
    other = my_int32_ptr;
    EXPECT_EQ(reinterpret_cast<uintptr_t>(&my_int32), other.GetPointerValue());
  }
}

TEST(MemoryTest, InvalidDeath) {
  const char kMemoryCheckFailedRegex[] = "Check failed";

  // Note: |Check...()| are defined to be "best effort" checks (and may always
  // return true). Thus these tests of invalid cases only reflect the current
  // implementation.

  // These tests depend on |int32_t| and |int64_t| having nontrivial alignment.
  static_assert(MOJO_ALIGNOF(int32_t) != 1,
                "int32_t does not require nontrivial alignment");
  static_assert(MOJO_ALIGNOF(int64_t) != 1,
                "int64_t does not require nontrivial alignment");

  // Null:
  {
    UserPointer<char> ptr(nullptr);
    char array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Put('x'), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(array, 5), kMemoryCheckFailedRegex);
  }
  {
    UserPointer<int32_t> ptr(nullptr);
    int32_t array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Put(123), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(array, 5), kMemoryCheckFailedRegex);
  }
  {
    UserPointer<int64_t> ptr(nullptr);
    int64_t array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Put(123), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(array, 5), kMemoryCheckFailedRegex);
  }
  // Also check a const pointer:
  {
    UserPointer<const int32_t> ptr(nullptr);
    int32_t array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
  }

  // Unaligned:
  {
    int32_t x[10];
    UserPointer<int32_t> ptr(
        reinterpret_cast<int32_t*>(reinterpret_cast<uintptr_t>(x) + 1));
    int32_t array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Put(123), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(array, 5), kMemoryCheckFailedRegex);
  }
  {
    int64_t x[10];
    UserPointer<int64_t> ptr(
        reinterpret_cast<int64_t*>(reinterpret_cast<uintptr_t>(x) + 1));
    int64_t array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Put(123), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(array, 5), kMemoryCheckFailedRegex);
  }
  // Also check a const pointer:
  {
    int32_t x[10];
    UserPointer<const int32_t> ptr(
        reinterpret_cast<const int32_t*>(reinterpret_cast<uintptr_t>(x) + 1));
    int32_t array[5] = {};
    EXPECT_DEATH_IF_SUPPORTED(ptr.Check(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.Get(), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(5), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(array, 5), kMemoryCheckFailedRegex);
  }

  // Count too big:
  {
    const size_t kTooBig =
        std::numeric_limits<size_t>::max() / sizeof(int32_t) + 1;
    int32_t x = 0;
    UserPointer<int32_t> ptr(&x);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(kTooBig), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(&x, kTooBig),
                              kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(&x, kTooBig),
                              kMemoryCheckFailedRegex);
  }
  {
    const size_t kTooBig =
        std::numeric_limits<size_t>::max() / sizeof(int64_t) + 1;
    int64_t x = 0;
    UserPointer<int64_t> ptr(&x);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(kTooBig), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(&x, kTooBig),
                              kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.PutArray(&x, kTooBig),
                              kMemoryCheckFailedRegex);
  }
  // Also check a const pointer:
  {
    const size_t kTooBig =
        std::numeric_limits<size_t>::max() / sizeof(int32_t) + 1;
    int32_t x = 0;
    UserPointer<const int32_t> ptr(&x);
    EXPECT_DEATH_IF_SUPPORTED(ptr.CheckArray(kTooBig), kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(ptr.GetArray(&x, kTooBig),
                              kMemoryCheckFailedRegex);
  }

  // TODO(vtl): Tests for |UserPointer{Reader,Writer,ReaderWriter}|.
}

}  // namespace
}  // namespace system
}  // namespace mojo