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