1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2014 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/edk/system/options_validation.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stddef.h>
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stdint.h>
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/c/system/macros.h"
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "testing/gtest/include/gtest/gtest.h"
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace edk {
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace {
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Declare a test options struct just as we do in actual public headers.
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezusing TestOptionsFlags = uint32_t;
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstatic_assert(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstruct MOJO_ALIGNAS(8) TestOptions {
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t struct_size;
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  TestOptionsFlags flags;
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t member1;
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t member2;
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez};
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezstatic_assert(sizeof(TestOptions) == 16, "TestOptions has wrong size");
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezconst uint32_t kSizeOfTestOptions = static_cast<uint32_t>(sizeof(TestOptions));
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezTEST(OptionsValidationTest, Valid) {
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const TestOptions kOptions = {kSizeOfTestOptions};
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UserOptionsReader<TestOptions> reader(&kOptions);
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(reader.is_valid());
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const TestOptions kOptions = {static_cast<uint32_t>(
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        offsetof(TestOptions, struct_size) + sizeof(uint32_t))};
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UserOptionsReader<TestOptions> reader(&kOptions);
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(reader.is_valid());
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const TestOptions kOptions = {
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        static_cast<uint32_t>(offsetof(TestOptions, flags) + sizeof(uint32_t))};
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UserOptionsReader<TestOptions> reader(&kOptions);
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(reader.is_valid());
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_FALSE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    TestOptions* options = reinterpret_cast<TestOptions*>(buf);
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    options->struct_size = kSizeOfTestOptions + 1;
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UserOptionsReader<TestOptions> reader(options);
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(reader.is_valid());
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  {
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MOJO_ALIGNAS(8) char buf[sizeof(TestOptions) + 100] = {};
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    TestOptions* options = reinterpret_cast<TestOptions*>(buf);
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    options->struct_size = kSizeOfTestOptions + 4;
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UserOptionsReader<TestOptions> reader(options);
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(reader.is_valid());
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, flags, reader));
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member1, reader));
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_TRUE(OPTIONS_STRUCT_HAS_MEMBER(TestOptions, member2, reader));
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezTEST(OptionsValidationTest, Invalid) {
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Size too small:
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (size_t i = 0; i < sizeof(uint32_t); i++) {
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    TestOptions options = {static_cast<uint32_t>(i)};
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UserOptionsReader<TestOptions> reader(&options);
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    EXPECT_FALSE(reader.is_valid()) << i;
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// These test invalid arguments that should cause death if we're being paranoid
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// about checking arguments (which we would want to do if, e.g., we were in a
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// true "kernel" situation, but we might not want to do otherwise for
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// performance reasons). Probably blatant errors like passing in null pointers
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// (for required pointer arguments) will still cause death, but perhaps not
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// predictably.
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezTEST(OptionsValidationTest, InvalidDeath) {
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#if defined(OFFICIAL_BUILD)
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const char kMemoryCheckFailedRegex[] = "";
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#else
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const char kMemoryCheckFailedRegex[] = "Check failed";
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#endif
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Null:
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  EXPECT_DEATH_IF_SUPPORTED(
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      { UserOptionsReader<TestOptions> reader((nullptr)); },
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      kMemoryCheckFailedRegex);
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Unaligned:
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  EXPECT_DEATH_IF_SUPPORTED(
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      {
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        UserOptionsReader<TestOptions> reader(
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            reinterpret_cast<const TestOptions*>(1));
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      },
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      kMemoryCheckFailedRegex);
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Note: The current implementation checks the size only after checking the
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // alignment versus that required for the |uint32_t| size, so it won't die in
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // the expected way if you pass, e.g., 4. So we have to manufacture a valid
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // pointer at an offset of alignment 4.
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  EXPECT_DEATH_IF_SUPPORTED(
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      {
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        uint32_t buffer[100] = {};
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        TestOptions* options = (reinterpret_cast<uintptr_t>(buffer) % 8 == 0)
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                   ? reinterpret_cast<TestOptions*>(&buffer[1])
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                   : reinterpret_cast<TestOptions*>(&buffer[0]);
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        options->struct_size = static_cast<uint32_t>(sizeof(TestOptions));
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        UserOptionsReader<TestOptions> reader(options);
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      },
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      kMemoryCheckFailedRegex);
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace edk
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
135