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/edk/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 edk { 15namespace { 16 17// Declare a test options struct just as we do in actual public headers. 18 19using TestOptionsFlags = uint32_t; 20 21static_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}; 28static_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(&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(&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(&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(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(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(&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#if defined(OFFICIAL_BUILD) 99 const char kMemoryCheckFailedRegex[] = ""; 100#else 101 const char kMemoryCheckFailedRegex[] = "Check failed"; 102#endif 103 104 // Null: 105 EXPECT_DEATH_IF_SUPPORTED( 106 { UserOptionsReader<TestOptions> reader((nullptr)); }, 107 kMemoryCheckFailedRegex); 108 109 // Unaligned: 110 EXPECT_DEATH_IF_SUPPORTED( 111 { 112 UserOptionsReader<TestOptions> reader( 113 reinterpret_cast<const TestOptions*>(1)); 114 }, 115 kMemoryCheckFailedRegex); 116 // Note: The current implementation checks the size only after checking the 117 // alignment versus that required for the |uint32_t| size, so it won't die in 118 // the expected way if you pass, e.g., 4. So we have to manufacture a valid 119 // pointer at an offset of alignment 4. 120 EXPECT_DEATH_IF_SUPPORTED( 121 { 122 uint32_t buffer[100] = {}; 123 TestOptions* options = (reinterpret_cast<uintptr_t>(buffer) % 8 == 0) 124 ? reinterpret_cast<TestOptions*>(&buffer[1]) 125 : reinterpret_cast<TestOptions*>(&buffer[0]); 126 options->struct_size = static_cast<uint32_t>(sizeof(TestOptions)); 127 UserOptionsReader<TestOptions> reader(options); 128 }, 129 kMemoryCheckFailedRegex); 130} 131 132} // namespace 133} // namespace edk 134} // namespace mojo 135