146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// found in the LICENSE file. 446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Functions to help with verifying various |Mojo...Options| structs from the 646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// (public, C) API. These are "extensible" structs, which all have |struct_size| 746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// as their first member. All fields (other than |struct_size|) are optional, 846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// but any |flags| specified must be known to the system (otherwise, an error of 946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// |MOJO_RESULT_UNIMPLEMENTED| should be returned). 1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#ifndef MOJO_SYSTEM_OPTIONS_VALIDATION_H_ 1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#define MOJO_SYSTEM_OPTIONS_VALIDATION_H_ 1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include <stddef.h> 1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include <stdint.h> 1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <algorithm> 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h" 2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "base/macros.h" 2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/public/c/system/types.h" 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "mojo/system/constants.h" 2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/system/memory.h" 2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "mojo/system/system_impl_export.h" 2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace mojo { 2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace system { 2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)template <class Options> 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class UserOptionsReader { 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public: 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Constructor from a |UserPointer<const Options>| (which it checks -- this 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // constructor has side effects!). 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Note: We initialize |options_reader_| without checking, since we do a check 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // in |GetSizeForReader()|. 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) explicit UserOptionsReader(UserPointer<const Options> options) 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) : options_reader_(UserPointer<const char>::Reader::NoCheck(), 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) options.template ReinterpretCast<const char>(), 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) GetSizeForReader(options)) { 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static_assert(offsetof(Options, struct_size) == 0, 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci "struct_size not first member of Options"); 421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // TODO(vtl): Enable when MSVC supports this (C++11 extended sizeof): 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // static_assert(sizeof(Options::struct_size) == sizeof(uint32_t), 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // "Options::struct_size not a uint32_t"); 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // (Or maybe assert that its type is uint32_t?) 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool is_valid() const { return !!options_reader_.GetPointer(); } 495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Options& options() const { 515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(is_valid()); 525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return *reinterpret_cast<const Options*>(options_reader_.GetPointer()); 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Checks that the given (variable-size) |options| passed to the constructor 565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // (plausibly) has a member at the given offset with the given size. You 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // probably want to use |OPTIONS_STRUCT_HAS_MEMBER()| instead. 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool HasMember(size_t offset, size_t size) const { 595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DCHECK(is_valid()); 605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // We assume that |offset| and |size| are reasonable, since they should come 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // from |offsetof(Options, some_member)| and |sizeof(Options::some_member)|, 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // respectively. 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return options().struct_size >= offset + size; 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private: 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static inline size_t GetSizeForReader(UserPointer<const Options> options) { 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) uint32_t struct_size = 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) options.template ReinterpretCast<const uint32_t>().Get(); 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (struct_size < sizeof(uint32_t)) 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 0; 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Check the full requested size. 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Note: Use |MOJO_ALIGNOF()| here to match the exact macro used in the 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // declaration of Options structs. 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) internal::CheckUserPointerWithSize<MOJO_ALIGNOF(Options)>(options.pointer_, 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) struct_size); 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) options.template ReinterpretCast<const char>().CheckArray(struct_size); 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // But we'll never look at more than |sizeof(Options)| bytes. 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return std::min(static_cast<size_t>(struct_size), sizeof(Options)); 8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) UserPointer<const char>::Reader options_reader_; 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(UserOptionsReader); 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Macro to invoke |UserOptionsReader<Options>::HasMember()| parametrized by 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// member name instead of offset and size. 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// (We can't just give |HasMember()| a member pointer template argument instead, 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// since there's no good/strictly-correct way to get an offset from that.) 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// TODO(vtl): With C++11, use |sizeof(Options::member)| instead of (the 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// contortion below). We might also be able to pull out the type |Options| from 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// |reader| (using |decltype|) instead of requiring a parameter. 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#define OPTIONS_STRUCT_HAS_MEMBER(Options, member, reader) \ 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) reader.HasMember(offsetof(Options, member), sizeof(reader.options().member)) 9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} // namespace system 10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)} // namespace mojo 10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#endif // MOJO_SYSTEM_OPTIONS_VALIDATION_H_ 104