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