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