• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace mojo {
14 namespace system {
15 namespace {
16 
17 // Declare a test options struct just as we do in actual public headers.
18 
19 typedef uint32_t TestOptionsFlags;
20 
21 MOJO_COMPILE_ASSERT(MOJO_ALIGNOF(int64_t) == 8, int64_t_has_weird_alignment);
22 struct MOJO_ALIGNAS(8) TestOptions {
23   uint32_t struct_size;
24   TestOptionsFlags flags;
25   uint32_t member1;
26   uint32_t member2;
27 };
28 MOJO_COMPILE_ASSERT(sizeof(TestOptions) == 16, TestOptions_has_wrong_size);
29 
30 const uint32_t kSizeOfTestOptions = static_cast<uint32_t>(sizeof(TestOptions));
31 
TEST(OptionsValidationTest,Valid)32 TEST(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 
TEST(OptionsValidationTest,Invalid)82 TEST(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.
TEST(OptionsValidationTest,InvalidDeath)97 TEST(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