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 // Serialization warnings are only recorded when DLOG is enabled. 6 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) 7 8 #include <stddef.h> 9 #include <utility> 10 11 #include "mojo/public/cpp/bindings/lib/array_internal.h" 12 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" 13 #include "mojo/public/cpp/bindings/lib/serialization.h" 14 #include "mojo/public/cpp/bindings/lib/validation_errors.h" 15 #include "mojo/public/cpp/system/message_pipe.h" 16 #include "mojo/public/interfaces/bindings/tests/serialization_test_structs.mojom.h" 17 #include "mojo/public/interfaces/bindings/tests/test_unions.mojom.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 20 namespace mojo { 21 namespace test { 22 namespace { 23 24 using mojo::internal::ContainerValidateParams; 25 26 // Creates an array of arrays of handles (2 X 3) for testing. 27 std::vector<base::Optional<std::vector<ScopedHandle>>> 28 CreateTestNestedHandleArray() { 29 std::vector<base::Optional<std::vector<ScopedHandle>>> array(2); 30 for (size_t i = 0; i < array.size(); ++i) { 31 std::vector<ScopedHandle> nested_array(3); 32 for (size_t j = 0; j < nested_array.size(); ++j) { 33 MessagePipe pipe; 34 nested_array[j] = ScopedHandle::From(std::move(pipe.handle1)); 35 } 36 array[i].emplace(std::move(nested_array)); 37 } 38 39 return array; 40 } 41 42 class SerializationWarningTest : public testing::Test { 43 public: 44 ~SerializationWarningTest() override {} 45 46 protected: 47 template <typename T> 48 void TestWarning(T obj, mojo::internal::ValidationError expected_warning) { 49 using MojomType = typename T::Struct::DataView; 50 51 warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); 52 53 mojo::internal::SerializationContext context; 54 mojo::Message message(0, 0, 0, 0, nullptr); 55 typename mojo::internal::MojomTypeTraits<MojomType>::Data::BufferWriter 56 writer; 57 mojo::internal::Serialize<MojomType>(obj, message.payload_buffer(), &writer, 58 &context); 59 EXPECT_EQ(expected_warning, warning_observer_.last_warning()); 60 } 61 62 template <typename MojomType, typename T> 63 void TestArrayWarning(T obj, 64 mojo::internal::ValidationError expected_warning, 65 const ContainerValidateParams* validate_params) { 66 warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); 67 68 mojo::internal::SerializationContext context; 69 mojo::Message message(0, 0, 0, 0, nullptr); 70 typename mojo::internal::MojomTypeTraits<MojomType>::Data::BufferWriter 71 writer; 72 mojo::internal::Serialize<MojomType>(obj, message.payload_buffer(), &writer, 73 validate_params, &context); 74 EXPECT_EQ(expected_warning, warning_observer_.last_warning()); 75 } 76 77 template <typename T> 78 void TestUnionWarning(T obj, 79 mojo::internal::ValidationError expected_warning) { 80 using MojomType = typename T::Struct::DataView; 81 82 warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE); 83 84 mojo::internal::SerializationContext context; 85 mojo::Message message(0, 0, 0, 0, nullptr); 86 typename mojo::internal::MojomTypeTraits<MojomType>::Data::BufferWriter 87 writer; 88 mojo::internal::Serialize<MojomType>(obj, message.payload_buffer(), &writer, 89 false, &context); 90 91 EXPECT_EQ(expected_warning, warning_observer_.last_warning()); 92 } 93 94 mojo::internal::SerializationWarningObserverForTesting warning_observer_; 95 }; 96 97 TEST_F(SerializationWarningTest, HandleInStruct) { 98 Struct2Ptr test_struct(Struct2::New()); 99 EXPECT_FALSE(test_struct->hdl.is_valid()); 100 101 TestWarning(std::move(test_struct), 102 mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE); 103 104 test_struct = Struct2::New(); 105 MessagePipe pipe; 106 test_struct->hdl = ScopedHandle::From(std::move(pipe.handle1)); 107 108 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE); 109 } 110 111 TEST_F(SerializationWarningTest, StructInStruct) { 112 Struct3Ptr test_struct(Struct3::New()); 113 EXPECT_TRUE(!test_struct->struct_1); 114 115 TestWarning(std::move(test_struct), 116 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER); 117 118 test_struct = Struct3::New(); 119 test_struct->struct_1 = Struct1::New(); 120 121 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE); 122 } 123 124 TEST_F(SerializationWarningTest, ArrayOfStructsInStruct) { 125 Struct4Ptr test_struct(Struct4::New()); 126 test_struct->data.resize(1); 127 128 TestWarning(std::move(test_struct), 129 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER); 130 131 test_struct = Struct4::New(); 132 test_struct->data.resize(0); 133 134 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE); 135 136 test_struct = Struct4::New(); 137 test_struct->data.resize(1); 138 test_struct->data[0] = Struct1::New(); 139 140 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE); 141 } 142 143 TEST_F(SerializationWarningTest, FixedArrayOfStructsInStruct) { 144 Struct5Ptr test_struct(Struct5::New()); 145 test_struct->pair.resize(1); 146 test_struct->pair[0] = Struct1::New(); 147 148 TestWarning(std::move(test_struct), 149 mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER); 150 151 test_struct = Struct5::New(); 152 test_struct->pair.resize(2); 153 test_struct->pair[0] = Struct1::New(); 154 test_struct->pair[1] = Struct1::New(); 155 156 TestWarning(std::move(test_struct), mojo::internal::VALIDATION_ERROR_NONE); 157 } 158 159 TEST_F(SerializationWarningTest, ArrayOfArraysOfHandles) { 160 using MojomType = ArrayDataView<ArrayDataView<ScopedHandle>>; 161 auto test_array = CreateTestNestedHandleArray(); 162 test_array[0] = base::nullopt; 163 (*test_array[1])[0] = ScopedHandle(); 164 165 ContainerValidateParams validate_params_0( 166 0, true, new ContainerValidateParams(0, true, nullptr)); 167 TestArrayWarning<MojomType>(std::move(test_array), 168 mojo::internal::VALIDATION_ERROR_NONE, 169 &validate_params_0); 170 171 test_array = CreateTestNestedHandleArray(); 172 test_array[0] = base::nullopt; 173 ContainerValidateParams validate_params_1( 174 0, false, new ContainerValidateParams(0, true, nullptr)); 175 TestArrayWarning<MojomType>( 176 std::move(test_array), 177 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, 178 &validate_params_1); 179 180 test_array = CreateTestNestedHandleArray(); 181 (*test_array[1])[0] = ScopedHandle(); 182 ContainerValidateParams validate_params_2( 183 0, true, new ContainerValidateParams(0, false, nullptr)); 184 TestArrayWarning<MojomType>( 185 std::move(test_array), 186 mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, 187 &validate_params_2); 188 } 189 190 TEST_F(SerializationWarningTest, ArrayOfStrings) { 191 using MojomType = ArrayDataView<StringDataView>; 192 193 std::vector<std::string> test_array(3); 194 for (size_t i = 0; i < test_array.size(); ++i) 195 test_array[i] = "hello"; 196 197 ContainerValidateParams validate_params_0( 198 0, true, new ContainerValidateParams(0, false, nullptr)); 199 TestArrayWarning<MojomType>(std::move(test_array), 200 mojo::internal::VALIDATION_ERROR_NONE, 201 &validate_params_0); 202 203 std::vector<base::Optional<std::string>> optional_test_array(3); 204 ContainerValidateParams validate_params_1( 205 0, false, new ContainerValidateParams(0, false, nullptr)); 206 TestArrayWarning<MojomType>( 207 std::move(optional_test_array), 208 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, 209 &validate_params_1); 210 211 test_array = std::vector<std::string>(2); 212 ContainerValidateParams validate_params_2( 213 3, true, new ContainerValidateParams(0, false, nullptr)); 214 TestArrayWarning<MojomType>( 215 std::move(test_array), 216 mojo::internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, 217 &validate_params_2); 218 } 219 220 TEST_F(SerializationWarningTest, StructInUnion) { 221 DummyStructPtr dummy(nullptr); 222 ObjectUnionPtr obj(ObjectUnion::New()); 223 obj->set_f_dummy(std::move(dummy)); 224 225 TestUnionWarning(std::move(obj), 226 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER); 227 } 228 229 TEST_F(SerializationWarningTest, UnionInUnion) { 230 PodUnionPtr pod(nullptr); 231 ObjectUnionPtr obj(ObjectUnion::New()); 232 obj->set_f_pod_union(std::move(pod)); 233 234 TestUnionWarning(std::move(obj), 235 mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER); 236 } 237 238 TEST_F(SerializationWarningTest, HandleInUnion) { 239 ScopedMessagePipeHandle pipe; 240 HandleUnionPtr handle(HandleUnion::New()); 241 handle->set_f_message_pipe(std::move(pipe)); 242 243 TestUnionWarning(std::move(handle), 244 mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE); 245 } 246 247 } // namespace 248 } // namespace test 249 } // namespace mojo 250 251 #endif 252