// 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