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 const TestOptions kOptions1 = {
34 kSizeOfTestOptions
35 };
36
37 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&kOptions1));
38 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions1));
39 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions1));
40 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions1));
41
42 const TestOptions kOptions2 = {
43 static_cast<uint32_t>(offsetof(TestOptions, struct_size) + sizeof(uint32_t))
44 };
45 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&kOptions2));
46 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions2));
47 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions2));
48 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions2));
49
50 const TestOptions kOptions3 = {
51 static_cast<uint32_t>(offsetof(TestOptions, flags) + sizeof(uint32_t))
52 };
53 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(&kOptions3));
54 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, &kOptions3));
55 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, &kOptions3));
56 EXPECT_FALSE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, &kOptions3));
57
58 MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
59 TestOptions* options = reinterpret_cast<TestOptions*>(buf);
60 options->struct_size = kSizeOfTestOptions + 1;
61 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(options));
62 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, options));
63 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, options));
64 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, options));
65
66 options->struct_size = kSizeOfTestOptions + 4;
67 EXPECT_TRUE(IsOptionsStructPointerAndSizeValid<TestOptions>(options));
68 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, flags, options));
69 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member1, options));
70 EXPECT_TRUE(HAS_OPTIONS_STRUCT_MEMBER(TestOptions, member2, options));
71 }
72
TEST(OptionsValidationTest,Invalid)73 TEST(OptionsValidationTest, Invalid) {
74 // Null:
75 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(NULL));
76
77 // Unaligned:
78 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(
79 reinterpret_cast<const void*>(1)));
80 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(
81 reinterpret_cast<const void*>(4)));
82
83 // Size too small:
84 for (size_t i = 0; i < sizeof(uint32_t); i++) {
85 TestOptions options = {static_cast<uint32_t>(i)};
86 EXPECT_FALSE(IsOptionsStructPointerAndSizeValid<TestOptions>(&options))
87 << i;
88 }
89 }
90
TEST(OptionsValidationTest,CheckFlags)91 TEST(OptionsValidationTest, CheckFlags) {
92 const TestOptions kOptions1 = {kSizeOfTestOptions, 0};
93 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 0u));
94 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 1u));
95 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 3u));
96 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, 7u));
97 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions1, ~0u));
98
99 const TestOptions kOptions2 = {kSizeOfTestOptions, 1};
100 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 0u));
101 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 1u));
102 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 3u));
103 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, 7u));
104 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions2, ~0u));
105
106 const TestOptions kOptions3 = {kSizeOfTestOptions, 2};
107 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 0u));
108 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 1u));
109 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 3u));
110 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, 7u));
111 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions3, ~0u));
112
113 const TestOptions kOptions4 = {kSizeOfTestOptions, 5};
114 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 0u));
115 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 1u));
116 EXPECT_FALSE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 3u));
117 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, 7u));
118 EXPECT_TRUE(AreOptionsFlagsAllKnown<TestOptions>(&kOptions4, ~0u));
119 }
120
TEST(OptionsValidationTest,ValidateOptionsStructPointerSizeAndFlags)121 TEST(OptionsValidationTest, ValidateOptionsStructPointerSizeAndFlags) {
122 const TestOptions kDefaultOptions = {kSizeOfTestOptions, 1u, 123u, 456u};
123
124 // Valid cases:
125
126 // "Normal":
127 {
128 const TestOptions kOptions = {kSizeOfTestOptions, 0u, 12u, 34u};
129 TestOptions validated_options = kDefaultOptions;
130 EXPECT_EQ(MOJO_RESULT_OK,
131 ValidateOptionsStructPointerSizeAndFlags<TestOptions>(
132 &kOptions, 3u, &validated_options));
133 EXPECT_EQ(kDefaultOptions.struct_size, validated_options.struct_size);
134 // Copied |flags|.
135 EXPECT_EQ(kOptions.flags, validated_options.flags);
136 // Didn't touch subsequent members.
137 EXPECT_EQ(kDefaultOptions.member1, validated_options.member1);
138 EXPECT_EQ(kDefaultOptions.member2, validated_options.member2);
139 }
140
141 // Doesn't actually have |flags|:
142 {
143 const TestOptions kOptions = {
144 static_cast<uint32_t>(sizeof(uint32_t)), 0u, 12u, 34u
145 };
146 TestOptions validated_options = kDefaultOptions;
147 EXPECT_EQ(MOJO_RESULT_OK,
148 ValidateOptionsStructPointerSizeAndFlags<TestOptions>(
149 &kOptions, 3u, &validated_options));
150 EXPECT_EQ(kDefaultOptions.struct_size, validated_options.struct_size);
151 // Didn't copy |flags|.
152 EXPECT_EQ(kDefaultOptions.flags, validated_options.flags);
153 // Didn't touch subsequent members.
154 EXPECT_EQ(kDefaultOptions.member1, validated_options.member1);
155 EXPECT_EQ(kDefaultOptions.member2, validated_options.member2);
156 }
157
158 // Invalid cases:
159
160 // Unaligned:
161 {
162 TestOptions validated_options = kDefaultOptions;
163 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
164 ValidateOptionsStructPointerSizeAndFlags<TestOptions>(
165 reinterpret_cast<const TestOptions*>(1), 3u,
166 &validated_options));
167 }
168
169 // |struct_size| too small:
170 {
171 const TestOptions kOptions = {1u, 0u, 12u, 34u};
172 TestOptions validated_options = kDefaultOptions;
173 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
174 ValidateOptionsStructPointerSizeAndFlags<TestOptions>(
175 &kOptions, 3u, &validated_options));
176 }
177
178 // Unknown |flag|:
179 {
180 const TestOptions kOptions = {kSizeOfTestOptions, 5u, 12u, 34u};
181 TestOptions validated_options = kDefaultOptions;
182 EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
183 ValidateOptionsStructPointerSizeAndFlags<TestOptions>(
184 &kOptions, 3u, &validated_options));
185 }
186 }
187
188 } // namespace
189 } // namespace system
190 } // namespace mojo
191