1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "mojo/system/options_validation.h"
6
7#include <stddef.h>
8#include <stdint.h>
9
10#include "mojo/public/c/system/macros.h"
11#include "testing/gtest/include/gtest/gtest.h"
12
13namespace mojo {
14namespace system {
15namespace {
16
17// Declare a test options struct just as we do in actual public headers.
18
19typedef uint32_t TestOptionsFlags;
20
21MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment);
22struct MOJO_ALIGNAS(8) TestOptions {
23  uint32_t struct_size;
24  TestOptionsFlags flags;
25  uint32_t member1;
26  uint32_t member2;
27};
28MOJO_COMPILE_ASSERT(sizeof(TestOptions) == 16, TestOptions_has_wrong_size);
29
30const uint32_t kSizeOfTestOptions = static_cast<uint32_t>(sizeof(TestOptions));
31
32TEST(OptionsValidationTest, Valid) {
33  {
34    const TestOptions kOptions = {kSizeOfTestOptions};
35    UserOptionsReader<TestOptions> reader(MakeUserPointer(&kOptions));
36    EXPECT_TRUE(reader.is_valid());
37    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
38    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
39    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
40  }
41  {
42    const TestOptions kOptions = {static_cast<uint32_t>(
43        offsetof(TestOptions, struct_size) + sizeof(uint32_t))};
44    UserOptionsReader<TestOptions> reader(MakeUserPointer(&kOptions));
45    EXPECT_TRUE(reader.is_valid());
46    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
47    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
48    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
49  }
50
51  {
52    const TestOptions kOptions = {
53        static_cast<uint32_t>(offsetof(TestOptions, flags) + sizeof(uint32_t))};
54    UserOptionsReader<TestOptions> reader(MakeUserPointer(&kOptions));
55    EXPECT_TRUE(reader.is_valid());
56    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
57    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
58    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
59  }
60  {
61    MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
62    TestOptions* options = reinterpret_cast<TestOptions*>(buf);
63    options->struct_size = kSizeOfTestOptions + 1;
64    UserOptionsReader<TestOptions> reader(MakeUserPointer(options));
65    EXPECT_TRUE(reader.is_valid());
66    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
67    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
68    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
69  }
70  {
71    MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
72    TestOptions* options = reinterpret_cast<TestOptions*>(buf);
73    options->struct_size = kSizeOfTestOptions + 4;
74    UserOptionsReader<TestOptions> reader(MakeUserPointer(options));
75    EXPECT_TRUE(reader.is_valid());
76    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
77    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
78    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
79  }
80}
81
82TEST(OptionsValidationTest, Invalid) {
83  // Size too small:
84  for (size_t i = 0; i < sizeof(uint32_t); i++) {
85    TestOptions options = {static_cast<uint32_t>(i)};
86    UserOptionsReader<TestOptions> reader(MakeUserPointer(&options));
87    EXPECT_FALSE(reader.is_valid()) << i;
88  }
89}
90
91// These test invalid arguments that should cause death if we're being paranoid
92// about checking arguments (which we would want to do if, e.g., we were in a
93// true "kernel" situation, but we might not want to do otherwise for
94// performance reasons). Probably blatant errors like passing in null pointers
95// (for required pointer arguments) will still cause death, but perhaps not
96// predictably.
97TEST(OptionsValidationTest, InvalidDeath) {
98  const char kMemoryCheckFailedRegex[] = "Check failed";
99
100  // Null:
101  EXPECT_DEATH_IF_SUPPORTED(
102      { UserOptionsReader<TestOptions> reader((NullUserPointer())); },
103      kMemoryCheckFailedRegex);
104
105  // Unaligned:
106  EXPECT_DEATH_IF_SUPPORTED(
107      {
108        UserOptionsReader<TestOptions> reader(
109            MakeUserPointer(reinterpret_cast<const TestOptions*>(1)));
110      },
111      kMemoryCheckFailedRegex);
112  // Note: The current implementation checks the size only after checking the
113  // alignment versus that required for the |uint32_t| size, so it won't die in
114  // the expected way if you pass, e.g., 4. So we have to manufacture a valid
115  // pointer at an offset of alignment 4.
116  EXPECT_DEATH_IF_SUPPORTED(
117      {
118        uint32_t buffer[100] = {};
119        TestOptions* options = (reinterpret_cast<uintptr_t>(buffer) % 8 == 0)
120                                   ? reinterpret_cast<TestOptions*>(&buffer[1])
121                                   : reinterpret_cast<TestOptions*>(&buffer[0]);
122        options->struct_size = static_cast<uint32_t>(sizeof(TestOptions));
123        UserOptionsReader<TestOptions> reader(MakeUserPointer(options));
124      },
125      kMemoryCheckFailedRegex);
126}
127
128}  // namespace
129}  // namespace system
130}  // namespace mojo
131