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/logging.h"
10 #include "base/macros.h"
11 #include "mojo/public/cpp/bindings/bindings_export.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 MOJO_CPP_BINDINGS_EXPORT const char* ValidationErrorToString(
80     ValidationError error);
81 
82 MOJO_CPP_BINDINGS_EXPORT void ReportValidationError(
83     ValidationContext* context,
84     ValidationError error,
85     const char* description = nullptr);
86 
87 MOJO_CPP_BINDINGS_EXPORT void ReportValidationErrorForMessage(
88     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.
95 class MOJO_CPP_BINDINGS_EXPORT ScopedSuppressValidationErrorLoggingForTests {
96  public:
97   ScopedSuppressValidationErrorLoggingForTests();
98   ~ScopedSuppressValidationErrorLoggingForTests();
99 
100  private:
101   const bool was_suppressed_;
102 
103   DISALLOW_COPY_AND_ASSIGN(ScopedSuppressValidationErrorLoggingForTests);
104 };
105 
106 // Only used by validation tests and when there is only one thread doing message
107 // validation.
108 class MOJO_CPP_BINDINGS_EXPORT ValidationErrorObserverForTesting {
109  public:
110   explicit ValidationErrorObserverForTesting(const base::Closure& callback);
111   ~ValidationErrorObserverForTesting();
112 
last_error()113   ValidationError last_error() const { return last_error_; }
set_last_error(ValidationError error)114   void set_last_error(ValidationError error) {
115     last_error_ = error;
116     callback_.Run();
117   }
118 
119  private:
120   ValidationError last_error_;
121   base::Closure callback_;
122 
123   DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting);
124 };
125 
126 // Used only by MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING. Don't use it directly.
127 //
128 // The function returns true if the error is recorded (by a
129 // SerializationWarningObserverForTesting object), false otherwise.
130 MOJO_CPP_BINDINGS_EXPORT bool ReportSerializationWarning(ValidationError error);
131 
132 // Only used by serialization tests and when there is only one thread doing
133 // message serialization.
134 class MOJO_CPP_BINDINGS_EXPORT SerializationWarningObserverForTesting {
135  public:
136   SerializationWarningObserverForTesting();
137   ~SerializationWarningObserverForTesting();
138 
last_warning()139   ValidationError last_warning() const { return last_warning_; }
set_last_warning(ValidationError error)140   void set_last_warning(ValidationError error) { last_warning_ = error; }
141 
142  private:
143   ValidationError last_warning_;
144 
145   DISALLOW_COPY_AND_ASSIGN(SerializationWarningObserverForTesting);
146 };
147 
148 }  // namespace internal
149 }  // namespace mojo
150 
151 // In debug build, logs a serialization warning if |condition| evaluates to
152 // true:
153 //   - if there is a SerializationWarningObserverForTesting object alive,
154 //     records |error| in it;
155 //   - otherwise, logs a fatal-level message.
156 // |error| is the validation error that will be triggered by the receiver
157 // of the serialzation result.
158 //
159 // In non-debug build, does nothing (not even compiling |condition|).
160 #define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(condition, error,    \
161                                                  description)         \
162   DLOG_IF(FATAL, (condition) && !ReportSerializationWarning(error))   \
163       << "The outgoing message will trigger "                         \
164       << ValidationErrorToString(error) << " at the receiving side (" \
165       << description << ").";
166 
167 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
168