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