// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ #define MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_ #include "base/callback.h" #include "base/component_export.h" #include "base/logging.h" #include "base/macros.h" #include "mojo/public/cpp/bindings/lib/validation_context.h" namespace mojo { class Message; namespace internal { enum ValidationError { // There is no validation error. VALIDATION_ERROR_NONE, // An object (struct or array) is not 8-byte aligned. VALIDATION_ERROR_MISALIGNED_OBJECT, // An object is not contained inside the message data, or it overlaps other // objects. VALIDATION_ERROR_ILLEGAL_MEMORY_RANGE, // A struct header doesn't make sense, for example: // - |num_bytes| is smaller than the size of the struct header. // - |num_bytes| and |version| don't match. // TODO(yzshen): Consider splitting it into two different error codes. Because // the former indicates someone is misbehaving badly whereas the latter could // be due to an inappropriately-modified .mojom file. VALIDATION_ERROR_UNEXPECTED_STRUCT_HEADER, // An array header doesn't make sense, for example: // - |num_bytes| is smaller than the size of the header plus the size required // to store |num_elements| elements. // - For fixed-size arrays, |num_elements| is different than the specified // size. VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER, // An encoded handle is illegal. VALIDATION_ERROR_ILLEGAL_HANDLE, // A non-nullable handle field is set to invalid handle. VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE, // An encoded pointer is illegal. VALIDATION_ERROR_ILLEGAL_POINTER, // A non-nullable pointer field is set to null. VALIDATION_ERROR_UNEXPECTED_NULL_POINTER, // An interface ID is illegal. VALIDATION_ERROR_ILLEGAL_INTERFACE_ID, // A non-nullable interface ID field is set to invalid. VALIDATION_ERROR_UNEXPECTED_INVALID_INTERFACE_ID, // |flags| in the message header is invalid. The flags are either // inconsistent with one another, inconsistent with other parts of the // message, or unexpected for the message receiver. For example the // receiver is expecting a request message but the flags indicate that // the message is a response message. VALIDATION_ERROR_MESSAGE_HEADER_INVALID_FLAGS, // |flags| in the message header indicates that a request ID is required but // there isn't one. VALIDATION_ERROR_MESSAGE_HEADER_MISSING_REQUEST_ID, // The |name| field in a message header contains an unexpected value. VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD, // Two parallel arrays which are supposed to represent a map have different // lengths. VALIDATION_ERROR_DIFFERENT_SIZED_ARRAYS_IN_MAP, // Attempted to deserialize a tagged union with an unknown tag. VALIDATION_ERROR_UNKNOWN_UNION_TAG, // A value of a non-extensible enum type is unknown. VALIDATION_ERROR_UNKNOWN_ENUM_VALUE, // Message deserialization failure, for example due to rejection by custom // validation logic. VALIDATION_ERROR_DESERIALIZATION_FAILED, // The message contains a too deeply nested value, for example a recursively // defined field which runtime value is too large. VALIDATION_ERROR_MAX_RECURSION_DEPTH, }; COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) const char* ValidationErrorToString(ValidationError error); COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) void ReportValidationError(ValidationContext* context, ValidationError error, const char* description = nullptr); COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) void ReportValidationErrorForMessage(mojo::Message* message, ValidationError error, const char* description = nullptr); // This class may be used by tests to suppress validation error logging. This is // not thread-safe and must only be instantiated on the main thread with no // other threads using Mojo bindings at the time of construction or destruction. class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ScopedSuppressValidationErrorLoggingForTests { public: ScopedSuppressValidationErrorLoggingForTests(); ~ScopedSuppressValidationErrorLoggingForTests(); private: const bool was_suppressed_; DISALLOW_COPY_AND_ASSIGN(ScopedSuppressValidationErrorLoggingForTests); }; // Only used by validation tests and when there is only one thread doing message // validation. class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ValidationErrorObserverForTesting { public: explicit ValidationErrorObserverForTesting(const base::Closure& callback); ~ValidationErrorObserverForTesting(); ValidationError last_error() const { return last_error_; } void set_last_error(ValidationError error) { last_error_ = error; callback_.Run(); } private: ValidationError last_error_; base::Closure callback_; DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting); }; // Used only by MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING. Don't use it directly. // // The function returns true if the error is recorded (by a // SerializationWarningObserverForTesting object), false otherwise. COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) bool ReportSerializationWarning(ValidationError error); // Only used by serialization tests and when there is only one thread doing // message serialization. class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) SerializationWarningObserverForTesting { public: SerializationWarningObserverForTesting(); ~SerializationWarningObserverForTesting(); ValidationError last_warning() const { return last_warning_; } void set_last_warning(ValidationError error) { last_warning_ = error; } private: ValidationError last_warning_; DISALLOW_COPY_AND_ASSIGN(SerializationWarningObserverForTesting); }; } // namespace internal } // namespace mojo // In debug build, logs a serialization warning if |condition| evaluates to // true: // - if there is a SerializationWarningObserverForTesting object alive, // records |error| in it; // - otherwise, logs a fatal-level message. // |error| is the validation error that will be triggered by the receiver // of the serialzation result. // // In non-debug build, does nothing (not even compiling |condition|). #define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(condition, error, \ description) \ DLOG_IF(FATAL, (condition) && !ReportSerializationWarning(error)) \ << "The outgoing message will trigger " \ << ValidationErrorToString(error) << " at the receiving side (" \ << description << ")."; #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_