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>>>
CreateTestNestedHandleArray()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:
~SerializationWarningTest()44   ~SerializationWarningTest() override {}
45 
46  protected:
47   template <typename T>
TestWarning(T obj,mojo::internal::ValidationError expected_warning)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>
TestArrayWarning(T obj,mojo::internal::ValidationError expected_warning,const ContainerValidateParams * validate_params)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>
TestUnionWarning(T obj,mojo::internal::ValidationError expected_warning)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 
TEST_F(SerializationWarningTest,HandleInStruct)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 
TEST_F(SerializationWarningTest,StructInStruct)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 
TEST_F(SerializationWarningTest,ArrayOfStructsInStruct)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 
TEST_F(SerializationWarningTest,FixedArrayOfStructsInStruct)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 
TEST_F(SerializationWarningTest,ArrayOfArraysOfHandles)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 
TEST_F(SerializationWarningTest,ArrayOfStrings)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 
TEST_F(SerializationWarningTest,StructInUnion)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 
TEST_F(SerializationWarningTest,UnionInUnion)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 
TEST_F(SerializationWarningTest,HandleInUnion)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