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 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
7
8 #include "base/callback.h"
9 #include "base/component_export.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "mojo/public/cpp/bindings/lib/validation_context.h"
13
14 namespace mojo {
15
16 class Message;
17
18 namespace internal {
19
20 enum ValidationError {
21 // There is no validation error.
22 VALIDATION_ERROR_NONE,
23 // An object (struct or array) is not 8-byte aligned.
24 VALIDATION_ERROR_MISALIGNED_OBJECT,
25 // An object is not contained inside the message data, or it overlaps other
26 // objects.
27 VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE,
28 // A struct header doesn't make sense, for example:
29 // - |num_bytes| is smaller than the size of the struct header.
30 // - |num_bytes| and |version| don't match.
31 // TODO(yzshen): Consider splitting it into two different error codes. Because
32 // the former indicates someone is misbehaving badly whereas the latter could
33 // be due to an inappropriately-modified .mojom file.
34 VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER,
35 // An array header doesn't make sense, for example:
36 // - |num_bytes| is smaller than the size of the header plus the size required
37 // to store |num_elements| elements.
38 // - For fixed-size arrays, |num_elements| is different than the specified
39 // size.
40 VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
41 // An encoded handle is illegal.
42 VALIDATION_ERROR_ILLEGAL_HANDLE,
43 // A non-nullable handle field is set to invalid handle.
44 VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
45 // An encoded pointer is illegal.
46 VALIDATION_ERROR_ILLEGAL_POINTER,
47 // A non-nullable pointer field is set to null.
48 VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
49 // An interface ID is illegal.
50 VALIDATION_ERROR_ILLEGAL_INTERFACE_ID,
51 // A non-nullable interface ID field is set to invalid.
52 VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID,
53 // |flags| in the message header is invalid. The flags are either
54 // inconsistent with one another, inconsistent with other parts of the
55 // message, or unexpected for the message receiver. For example the
56 // receiver is expecting a request message but the flags indicate that
57 // the message is a response message.
58 VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS,
59 // |flags| in the message header indicates that a request ID is required but
60 // there isn't one.
61 VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID,
62 // The |name| field in a message header contains an unexpected value.
63 VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD,
64 // Two parallel arrays which are supposed to represent a map have different
65 // lengths.
66 VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP,
67 // Attempted to deserialize a tagged union with an unknown tag.
68 VALIDATION_ERROR_UNKNOWN_UNION_TAG,
69 // A value of a non-extensible enum type is unknown.
70 VALIDATION_ERROR_UNKNOWN_ENUM_VALUE,
71 // Message deserialization failure, for example due to rejection by custom
72 // validation logic.
73 VALIDATION_ERROR_DESERIALIZATION_FAILED,
74 // The message contains a too deeply nested value, for example a recursively
75 // defined field which runtime value is too large.
76 VALIDATION_ERROR_MAX_RECURSION_DEPTH,
77 };
78
79 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
80 const char* ValidationErrorToString(ValidationError error);
81
82 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
83 void ReportValidationError(ValidationContext* context,
84 ValidationError error,
85 const char* description = nullptr);
86
87 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
88 void ReportValidationErrorForMessage(mojo::Message* message,
89 ValidationError error,
90 const char* description = nullptr);
91
92 // This class may be used by tests to suppress validation error logging. This is
93 // not thread-safe and must only be instantiated on the main thread with no
94 // other threads using Mojo bindings at the time of construction or destruction.
COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)95 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
96 ScopedSuppressValidationErrorLoggingForTests {
97 public:
98 ScopedSuppressValidationErrorLoggingForTests();
99 ~ScopedSuppressValidationErrorLoggingForTests();
100
101 private:
102 const bool was_suppressed_;
103
104 DISALLOW_COPY_AND_ASSIGN(ScopedSuppressValidationErrorLoggingForTests);
105 };
106
107 // Only used by validation tests and when there is only one thread doing message
108 // validation.
COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)109 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
110 ValidationErrorObserverForTesting {
111 public:
112 explicit ValidationErrorObserverForTesting(const base::Closure& callback);
113 ~ValidationErrorObserverForTesting();
114
115 ValidationError last_error() const { return last_error_; }
116 void set_last_error(ValidationError error) {
117 last_error_ = error;
118 callback_.Run();
119 }
120
121 private:
122 ValidationError last_error_;
123 base::Closure callback_;
124
125 DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting);
126 };
127
128 // Used only by MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING. Don't use it directly.
129 //
130 // The function returns true if the error is recorded (by a
131 // SerializationWarningObserverForTesting object), false otherwise.
132 COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
133 bool ReportSerializationWarning(ValidationError error);
134
135 // Only used by serialization tests and when there is only one thread doing
136 // message serialization.
COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)137 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
138 SerializationWarningObserverForTesting {
139 public:
140 SerializationWarningObserverForTesting();
141 ~SerializationWarningObserverForTesting();
142
143 ValidationError last_warning() const { return last_warning_; }
144 void set_last_warning(ValidationError error) { last_warning_ = error; }
145
146 private:
147 ValidationError last_warning_;
148
149 DISALLOW_COPY_AND_ASSIGN(SerializationWarningObserverForTesting);
150 };
151
152 } // namespace internal
153 } // namespace mojo
154
155 // In debug build, logs a serialization warning if |condition| evaluates to
156 // true:
157 // - if there is a SerializationWarningObserverForTesting object alive,
158 // records |error| in it;
159 // - otherwise, logs a fatal-level message.
160 // |error| is the validation error that will be triggered by the receiver
161 // of the serialzation result.
162 //
163 // In non-debug build, does nothing (not even compiling |condition|).
164 #define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(condition, error, \
165 description) \
166 DLOG_IF(FATAL, (condition) && !ReportSerializationWarning(error)) \
167 << "The outgoing message will trigger " \
168 << ValidationErrorToString(error) << " at the receiving side (" \
169 << description << ").";
170
171 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
172