// 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 <stddef.h> #include <stdint.h> #include <limits> #include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/bindings/lib/validation_context.h" #include "mojo/public/cpp/system/core.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace test { namespace { using Handle_Data = mojo::internal::Handle_Data; using AssociatedEndpointHandle_Data = mojo::internal::AssociatedEndpointHandle_Data; const void* ToPtr(uintptr_t ptr) { return reinterpret_cast<const void*>(ptr); } #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON) TEST(ValidationContextTest, ConstructorRangeOverflow) { { // Test memory range overflow. internal::ValidationContext context( ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 5000, 0, 0); EXPECT_FALSE(context.IsValidRange( ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 1)); EXPECT_FALSE(context.ClaimMemory( ToPtr(std::numeric_limits<uintptr_t>::max() - 3000), 1)); } if (sizeof(size_t) <= sizeof(uint32_t)) return; { // Test handle index range overflow. size_t num_handles = static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 5; internal::ValidationContext context(ToPtr(0), 0, num_handles, 0); EXPECT_FALSE(context.ClaimHandle(Handle_Data(0))); EXPECT_FALSE(context.ClaimHandle( Handle_Data(std::numeric_limits<uint32_t>::max() - 1))); EXPECT_TRUE(context.ClaimHandle( Handle_Data(internal::kEncodedInvalidHandleValue))); } { size_t num_associated_endpoint_handles = static_cast<size_t>(std::numeric_limits<uint32_t>::max()) + 5; internal::ValidationContext context(ToPtr(0), 0, 0, num_associated_endpoint_handles); EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(0))); EXPECT_FALSE( context.ClaimAssociatedEndpointHandle(AssociatedEndpointHandle_Data( std::numeric_limits<uint32_t>::max() - 1))); EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); } } #endif TEST(ValidationContextTest, IsValidRange) { { internal::ValidationContext context(ToPtr(1234), 100, 0, 0); // Basics. EXPECT_FALSE(context.IsValidRange(ToPtr(100), 5)); EXPECT_FALSE(context.IsValidRange(ToPtr(1230), 50)); EXPECT_TRUE(context.IsValidRange(ToPtr(1234), 5)); EXPECT_TRUE(context.IsValidRange(ToPtr(1240), 50)); EXPECT_TRUE(context.IsValidRange(ToPtr(1234), 100)); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 101)); EXPECT_FALSE(context.IsValidRange(ToPtr(1240), 100)); EXPECT_FALSE(context.IsValidRange(ToPtr(1333), 5)); EXPECT_FALSE(context.IsValidRange(ToPtr(2234), 5)); // ClaimMemory() updates the valid range. EXPECT_TRUE(context.ClaimMemory(ToPtr(1254), 10)); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 1)); EXPECT_FALSE(context.IsValidRange(ToPtr(1254), 10)); EXPECT_FALSE(context.IsValidRange(ToPtr(1263), 1)); EXPECT_FALSE(context.IsValidRange(ToPtr(1263), 10)); EXPECT_TRUE(context.IsValidRange(ToPtr(1264), 10)); EXPECT_TRUE(context.IsValidRange(ToPtr(1264), 70)); EXPECT_FALSE(context.IsValidRange(ToPtr(1264), 71)); } { internal::ValidationContext context(ToPtr(1234), 100, 0, 0); // Should return false for empty ranges. EXPECT_FALSE(context.IsValidRange(ToPtr(0), 0)); EXPECT_FALSE(context.IsValidRange(ToPtr(1200), 0)); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 0)); EXPECT_FALSE(context.IsValidRange(ToPtr(1240), 0)); EXPECT_FALSE(context.IsValidRange(ToPtr(2234), 0)); } { // The valid memory range is empty. internal::ValidationContext context(ToPtr(1234), 0, 0, 0); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 1)); EXPECT_FALSE(context.IsValidRange(ToPtr(1234), 0)); } { internal::ValidationContext context( ToPtr(std::numeric_limits<uintptr_t>::max() - 2000), 1000, 0, 0); // Test overflow. EXPECT_FALSE(context.IsValidRange( ToPtr(std::numeric_limits<uintptr_t>::max() - 1500), 4000)); EXPECT_FALSE(context.IsValidRange( ToPtr(std::numeric_limits<uintptr_t>::max() - 1500), std::numeric_limits<uint32_t>::max())); // This should be fine. EXPECT_TRUE(context.IsValidRange( ToPtr(std::numeric_limits<uintptr_t>::max() - 1500), 200)); } } TEST(ValidationContextTest, ClaimHandle) { { internal::ValidationContext context(ToPtr(0), 0, 10, 0); // Basics. EXPECT_TRUE(context.ClaimHandle(Handle_Data(0))); EXPECT_FALSE(context.ClaimHandle(Handle_Data(0))); EXPECT_TRUE(context.ClaimHandle(Handle_Data(9))); EXPECT_FALSE(context.ClaimHandle(Handle_Data(10))); // Should fail because it is smaller than the max index that has been // claimed. EXPECT_FALSE(context.ClaimHandle(Handle_Data(8))); // Should return true for invalid handle. EXPECT_TRUE(context.ClaimHandle( Handle_Data(internal::kEncodedInvalidHandleValue))); EXPECT_TRUE(context.ClaimHandle( Handle_Data(internal::kEncodedInvalidHandleValue))); } { // No handle to claim. internal::ValidationContext context(ToPtr(0), 0, 0, 0); EXPECT_FALSE(context.ClaimHandle(Handle_Data(0))); // Should still return true for invalid handle. EXPECT_TRUE(context.ClaimHandle( Handle_Data(internal::kEncodedInvalidHandleValue))); } { // Test the case that |num_handles| is the same value as // |internal::kEncodedInvalidHandleValue|. EXPECT_EQ(internal::kEncodedInvalidHandleValue, std::numeric_limits<uint32_t>::max()); internal::ValidationContext context( ToPtr(0), 0, std::numeric_limits<uint32_t>::max(), 0); EXPECT_TRUE(context.ClaimHandle( Handle_Data(std::numeric_limits<uint32_t>::max() - 1))); EXPECT_FALSE(context.ClaimHandle( Handle_Data(std::numeric_limits<uint32_t>::max() - 1))); EXPECT_FALSE(context.ClaimHandle(Handle_Data(0))); // Should still return true for invalid handle. EXPECT_TRUE(context.ClaimHandle( Handle_Data(internal::kEncodedInvalidHandleValue))); } } TEST(ValidationContextTest, ClaimAssociatedEndpointHandle) { { internal::ValidationContext context(ToPtr(0), 0, 0, 10); // Basics. EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(0))); EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(0))); EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(9))); EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(10))); // Should fail because it is smaller than the max index that has been // claimed. EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(8))); // Should return true for invalid handle. EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); } { // No handle to claim. internal::ValidationContext context(ToPtr(0), 0, 0, 0); EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(0))); // Should still return true for invalid handle. EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); } { // Test the case that |num_associated_endpoint_handles| is the same value as // |internal::kEncodedInvalidHandleValue|. EXPECT_EQ(internal::kEncodedInvalidHandleValue, std::numeric_limits<uint32_t>::max()); internal::ValidationContext context(ToPtr(0), 0, 0, std::numeric_limits<uint32_t>::max()); EXPECT_TRUE( context.ClaimAssociatedEndpointHandle(AssociatedEndpointHandle_Data( std::numeric_limits<uint32_t>::max() - 1))); EXPECT_FALSE( context.ClaimAssociatedEndpointHandle(AssociatedEndpointHandle_Data( std::numeric_limits<uint32_t>::max() - 1))); EXPECT_FALSE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(0))); // Should still return true for invalid handle. EXPECT_TRUE(context.ClaimAssociatedEndpointHandle( AssociatedEndpointHandle_Data(internal::kEncodedInvalidHandleValue))); } } TEST(ValidationContextTest, ClaimMemory) { { internal::ValidationContext context(ToPtr(1000), 2000, 0, 0); // Basics. EXPECT_FALSE(context.ClaimMemory(ToPtr(500), 100)); EXPECT_FALSE(context.ClaimMemory(ToPtr(800), 300)); EXPECT_TRUE(context.ClaimMemory(ToPtr(1000), 100)); EXPECT_FALSE(context.ClaimMemory(ToPtr(1099), 100)); EXPECT_TRUE(context.ClaimMemory(ToPtr(1100), 200)); EXPECT_FALSE(context.ClaimMemory(ToPtr(2000), 1001)); EXPECT_TRUE(context.ClaimMemory(ToPtr(2000), 500)); EXPECT_FALSE(context.ClaimMemory(ToPtr(2000), 500)); EXPECT_FALSE(context.ClaimMemory(ToPtr(1400), 100)); EXPECT_FALSE(context.ClaimMemory(ToPtr(3000), 1)); EXPECT_TRUE(context.ClaimMemory(ToPtr(2500), 500)); } { // No memory to claim. internal::ValidationContext context(ToPtr(10000), 0, 0, 0); EXPECT_FALSE(context.ClaimMemory(ToPtr(10000), 1)); EXPECT_FALSE(context.ClaimMemory(ToPtr(10000), 0)); } { internal::ValidationContext context( ToPtr(std::numeric_limits<uintptr_t>::max() - 1000), 500, 0, 0); // Test overflow. EXPECT_FALSE(context.ClaimMemory( ToPtr(std::numeric_limits<uintptr_t>::max() - 750), 4000)); EXPECT_FALSE( context.ClaimMemory(ToPtr(std::numeric_limits<uintptr_t>::max() - 750), std::numeric_limits<uint32_t>::max())); // This should be fine. EXPECT_TRUE(context.ClaimMemory( ToPtr(std::numeric_limits<uintptr_t>::max() - 750), 200)); } } } // namespace } // namespace test } // namespace mojo