// 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 #include #include #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 my_char_ptr(&my_char); UserPointer my_int32_ptr(&my_int32); UserPointer 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 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 other((NullUserPointer())); EXPECT_TRUE(other.IsNull()); // Conversion to "const": other = my_char_ptr; EXPECT_EQ('x', other.Get()); } // Default constructor: { UserPointer 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 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::Reader reader(my_int64_array_ptr, 5); EXPECT_EQ(456, reader.GetPointer()[0]); EXPECT_EQ(321, reader.GetPointer()[4]); } // Non-const to const: { UserPointer::Reader reader(my_int64_array_ptr.At(3), 1); const int64_t* ptr = reader.GetPointer(); EXPECT_EQ(654, *ptr); } // |UserPointer<>::Writer|: { UserPointer::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::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 other(my_int32_ptr.ReinterpretCast()); 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 other; EXPECT_EQ(0u, other.GetPointerValue()); other = my_int32_ptr; EXPECT_EQ(reinterpret_cast(&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. MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int32_t) != 1, int32_t_does_not_have_to_be_aligned); MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) != 1, int64_t_does_not_have_to_be_aligned); // Null: { UserPointer ptr(NULL); 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 ptr(NULL); 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 ptr(NULL); 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 ptr(NULL); 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 ptr( reinterpret_cast(reinterpret_cast(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 ptr( reinterpret_cast(reinterpret_cast(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 ptr( reinterpret_cast(reinterpret_cast(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::max() / sizeof(int32_t) + 1; int32_t x = 0; UserPointer 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::max() / sizeof(int64_t) + 1; int64_t x = 0; UserPointer 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::max() / sizeof(int32_t) + 1; int32_t x = 0; UserPointer 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