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