Index: mojo/public/cpp/bindings/lib/array_internal.h |
diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h |
index 190f6da9ea1c95be544fd21e082968e2a2e51630..f74c857a35930e243010c459d1806c4694db4b06 100644 |
--- a/mojo/public/cpp/bindings/lib/array_internal.h |
+++ b/mojo/public/cpp/bindings/lib/array_internal.h |
@@ -8,10 +8,12 @@ |
#include <new> |
#include <vector> |
+#include "mojo/public/c/system/macros.h" |
#include "mojo/public/cpp/bindings/lib/bindings_internal.h" |
#include "mojo/public/cpp/bindings/lib/bindings_serialization.h" |
#include "mojo/public/cpp/bindings/lib/bounds_checker.h" |
#include "mojo/public/cpp/bindings/lib/buffer.h" |
+#include "mojo/public/cpp/bindings/lib/template_util.h" |
#include "mojo/public/cpp/bindings/lib/validation_errors.h" |
#include "mojo/public/cpp/environment/logging.h" |
@@ -110,11 +112,32 @@ struct ArrayDataTraits<bool> { |
} |
}; |
+// Array type information needed for valdiation. |
+template <uint32_t in_expected_num_elements, |
+ bool in_element_nullable, |
+ typename InElementValidateParams> |
+class ArrayValidateParams { |
+ public: |
+ // Validation information for elements. It is either another specialization of |
+ // ArrayValidateParams (if elements are arrays) or NoValidateParams. |
+ typedef InElementValidateParams ElementValidateParams; |
+ |
+ // If |expected_num_elements| is not 0, the array is expected to have exactly |
+ // that number of elements. |
+ static const uint32_t expected_num_elements = in_expected_num_elements; |
+ // Whether the elements are nullable. |
+ static const bool element_nullable = in_element_nullable; |
+}; |
+ |
+// NoValidateParams is used to indicate the end of an ArrayValidateParams chain. |
+class NoValidateParams { |
+}; |
+ |
// What follows is code to support the serialization of Array_Data<T>. There |
// are two interesting cases: arrays of primitives and arrays of objects. |
// Arrays of objects are represented as arrays of pointers to objects. |
-template <typename T, bool kIsHandle> struct ArraySerializationHelper; |
+template <typename T, bool is_handle> struct ArraySerializationHelper; |
template <typename T> |
struct ArraySerializationHelper<T, false> { |
@@ -130,9 +153,15 @@ struct ArraySerializationHelper<T, false> { |
std::vector<Handle>* handles) { |
} |
+ template <bool element_nullable, typename ElementValidateParams> |
static bool ValidateElements(const ArrayHeader* header, |
const ElementType* elements, |
BoundsChecker* bounds_checker) { |
+ MOJO_COMPILE_ASSERT(!element_nullable, |
+ Primitive_type_should_be_non_nullable); |
+ MOJO_COMPILE_ASSERT( |
+ (IsSame<ElementValidateParams, NoValidateParams>::value), |
+ Primitive_type_should_not_have_array_validate_params); |
return true; |
} |
}; |
@@ -149,9 +178,27 @@ struct ArraySerializationHelper<Handle, true> { |
ElementType* elements, |
std::vector<Handle>* handles); |
+ template <bool element_nullable, typename ElementValidateParams> |
static bool ValidateElements(const ArrayHeader* header, |
const ElementType* elements, |
- BoundsChecker* bounds_checker); |
+ BoundsChecker* bounds_checker) { |
+ MOJO_COMPILE_ASSERT( |
+ (IsSame<ElementValidateParams, NoValidateParams>::value), |
+ Handle_type_should_not_have_array_validate_params); |
+ |
+ for (uint32_t i = 0; i < header->num_elements; ++i) { |
+ if (IsNonNullableValidationEnabled() && !element_nullable && |
+ elements[i].value() == kEncodedInvalidHandleValue) { |
+ ReportValidationError(VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE); |
+ return false; |
+ } |
+ if (!bounds_checker->ClaimHandle(elements[i])) { |
+ ReportValidationError(VALIDATION_ERROR_ILLEGAL_HANDLE); |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
}; |
template <typename H> |
@@ -172,11 +219,13 @@ struct ArraySerializationHelper<H, true> { |
header, elements, handles); |
} |
+ template <bool element_nullable, typename ElementValidateParams> |
static bool ValidateElements(const ArrayHeader* header, |
const ElementType* elements, |
BoundsChecker* bounds_checker) { |
- return ArraySerializationHelper<Handle, true>::ValidateElements( |
- header, elements, bounds_checker); |
+ return ArraySerializationHelper<Handle, true>:: |
+ ValidateElements<element_nullable, ElementValidateParams>( |
+ header, elements, bounds_checker); |
} |
}; |
@@ -198,19 +247,46 @@ struct ArraySerializationHelper<P*, false> { |
Decode(&elements[i], handles); |
} |
+ template <bool element_nullable, typename ElementValidateParams> |
static bool ValidateElements(const ArrayHeader* header, |
const ElementType* elements, |
BoundsChecker* bounds_checker) { |
for (uint32_t i = 0; i < header->num_elements; ++i) { |
+ if (IsNonNullableValidationEnabled() && !element_nullable && |
+ !elements[i].offset) { |
+ ReportValidationError(VALIDATION_ERROR_UNEXPECTED_NULL_POINTER); |
+ return false; |
+ } |
if (!ValidateEncodedPointer(&elements[i].offset)) { |
ReportValidationError(VALIDATION_ERROR_ILLEGAL_POINTER); |
return false; |
} |
- if (!P::Validate(DecodePointerRaw(&elements[i].offset), bounds_checker)) |
+ if (!ValidateCaller<P, ElementValidateParams>::Run( |
+ DecodePointerRaw(&elements[i].offset), bounds_checker)) { |
return false; |
+ } |
} |
return true; |
} |
+ |
+ private: |
+ template <typename T, typename Params> |
+ struct ValidateCaller { |
+ static bool Run(const void* data, BoundsChecker* bounds_checker) { |
+ MOJO_COMPILE_ASSERT( |
+ (IsSame<Params, NoValidateParams>::value), |
+ Struct_type_should_not_have_array_validate_params); |
+ |
+ return T::Validate(data, bounds_checker); |
+ } |
+ }; |
+ |
+ template <typename T, typename Params> |
+ struct ValidateCaller<Array_Data<T>, Params> { |
+ static bool Run(const void* data, BoundsChecker* bounds_checker) { |
+ return Array_Data<T>::template Validate<Params>(data, bounds_checker); |
+ } |
+ }; |
}; |
template <typename T> |
@@ -229,11 +305,8 @@ class Array_Data { |
num_elements); |
} |
- // If expected_num_elements is not zero, the actual number of elements in the |
- // header must match that value or the message is rejected. |
- static bool Validate(const void* data, |
- BoundsChecker* bounds_checker, |
- uint32_t expected_num_elements = 0) { |
+ template <typename Params> |
+ static bool Validate(const void* data, BoundsChecker* bounds_checker) { |
if (!data) |
return true; |
if (!IsAligned(data)) { |
@@ -250,8 +323,8 @@ class Array_Data { |
ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER); |
return false; |
} |
- if (expected_num_elements != 0 && |
- header->num_elements != expected_num_elements) { |
+ if (Params::expected_num_elements != 0 && |
+ header->num_elements != Params::expected_num_elements) { |
ReportValidationError(VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER); |
return false; |
} |
@@ -261,8 +334,9 @@ class Array_Data { |
} |
const Array_Data<T>* object = static_cast<const Array_Data<T>*>(data); |
- return Helper::ValidateElements(&object->header_, object->storage(), |
- bounds_checker); |
+ return Helper::template ValidateElements< |
+ Params::element_nullable, typename Params::ElementValidateParams>( |
+ &object->header_, object->storage(), bounds_checker); |
} |
size_t size() const { return header_.num_elements; } |