tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pickle.h (10964B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style license that can be
      5 // found in the LICENSE file.
      6 
      7 #ifndef BASE_PICKLE_H__
      8 #define BASE_PICKLE_H__
      9 
     10 #include <string>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/logging.h"
     14 #include "base/string16.h"
     15 
     16 #include "mozilla/BufferList.h"
     17 #include "mozilla/mozalloc.h"
     18 #include "mozilla/TimeStamp.h"
     19 #if !defined(FUZZING) && (!defined(RELEASE_OR_BETA) || defined(DEBUG))
     20 #  define MOZ_PICKLE_SENTINEL_CHECKING
     21 #endif
     22 class Pickle;
     23 class PickleIterator {
     24 public:
     25  explicit PickleIterator(const Pickle& pickle);
     26 
     27 private:
     28  friend class Pickle;
     29 
     30  mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_;
     31 
     32  template <typename T>
     33  void CopyInto(T* dest);
     34 };
     35 
     36 // This class provides facilities for basic binary value packing and unpacking.
     37 //
     38 // The Pickle class supports appending primitive values (ints, strings, etc.)
     39 // to a pickle instance.  The Pickle instance grows its internal memory buffer
     40 // dynamically to hold the sequence of primitive values.   The internal memory
     41 // buffer is exposed as the "data" of the Pickle.  This "data" can be passed
     42 // to a Pickle object to initialize it for reading.
     43 //
     44 // When reading from a Pickle object, it is important for the consumer to know
     45 // what value types to read and in what order to read them as the Pickle does
     46 // not keep track of the type of data written to it.
     47 //
     48 // The Pickle's data has a header which contains the size of the Pickle's
     49 // payload.  It can optionally support additional space in the header.  That
     50 // space is controlled by the header_size parameter passed to the Pickle
     51 // constructor.
     52 //
     53 class Pickle {
     54 public:
     55  ~Pickle();
     56 
     57  Pickle() = delete;
     58 
     59  // Initialize a Pickle object with the specified header size in bytes, which
     60  // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
     61  // will be rounded up to ensure that the header size is 32bit-aligned.
     62  explicit Pickle(uint32_t header_size, size_t segment_capacity = 0);
     63 
     64  Pickle(uint32_t header_size, const char* data, uint32_t length);
     65 
     66  Pickle(const Pickle& other) = delete;
     67 
     68  Pickle(Pickle&& other);
     69 
     70  // Performs a deep copy.
     71  Pickle& operator=(const Pickle& other) = delete;
     72 
     73  Pickle& operator=(Pickle&& other);
     74 
     75  void CopyFrom(const Pickle& other);
     76 
     77  // Returns the size of the Pickle's data.
     78  uint32_t size() const { return header_size_ + header_->payload_size; }
     79 
     80  typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
     81 
     82  const BufferList& Buffers() const { return buffers_; }
     83 
     84  uint32_t CurrentSize() const { return buffers_.Size(); }
     85 
     86  // Methods for reading the payload of the Pickle.  To read from the start of
     87  // the Pickle, initialize *iter to NULL.  If successful, these methods return
     88  // true.  Otherwise, false is returned to indicate that the result could not
     89  // be extracted.
     90  [[nodiscard]] bool ReadBool(PickleIterator* iter, bool* result) const;
     91  [[nodiscard]] bool ReadInt16(PickleIterator* iter, int16_t* result) const;
     92  [[nodiscard]] bool ReadUInt16(PickleIterator* iter, uint16_t* result) const;
     93  [[nodiscard]] bool ReadShort(PickleIterator* iter, short* result) const;
     94  [[nodiscard]] bool ReadInt(PickleIterator* iter, int* result) const;
     95  [[nodiscard]] bool ReadLong(PickleIterator* iter, long* result) const;
     96  [[nodiscard]] bool ReadULong(PickleIterator* iter,
     97                               unsigned long* result) const;
     98  [[nodiscard]] bool ReadInt32(PickleIterator* iter, int32_t* result) const;
     99  [[nodiscard]] bool ReadUInt32(PickleIterator* iter, uint32_t* result) const;
    100  [[nodiscard]] bool ReadInt64(PickleIterator* iter, int64_t* result) const;
    101  [[nodiscard]] bool ReadUInt64(PickleIterator* iter, uint64_t* result) const;
    102  [[nodiscard]] bool ReadDouble(PickleIterator* iter, double* result) const;
    103  [[nodiscard]] bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const;
    104  [[nodiscard]] bool ReadUnsignedChar(PickleIterator* iter,
    105                                      unsigned char* result) const;
    106  [[nodiscard]] bool ReadString(PickleIterator* iter,
    107                                std::string* result) const;
    108  [[nodiscard]] bool ReadWString(PickleIterator* iter,
    109                                 std::wstring* result) const;
    110  [[nodiscard]] bool ReadBytesInto(PickleIterator* iter, void* data,
    111                                   uint32_t length) const;
    112 
    113  // Safer version of ReadInt() checks for the result not being negative.
    114  // Use it for reading the object sizes.
    115  [[nodiscard]] bool ReadLength(PickleIterator* iter, int* result) const;
    116 
    117  [[nodiscard]] bool IgnoreBytes(PickleIterator* iter, uint32_t length) const;
    118 
    119  [[nodiscard]] bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const
    120 #ifdef MOZ_PICKLE_SENTINEL_CHECKING
    121      ;
    122 #else
    123  {
    124    return true;
    125  }
    126 #endif
    127 
    128  template <class T>
    129  [[nodiscard]] bool ReadScalar(PickleIterator* iter, T* result) const {
    130    static_assert(std::is_arithmetic<T>::value);
    131    static_assert(!std::is_same<typename std::remove_cv<T>::type, bool>::value);
    132 
    133    DCHECK(iter);
    134 
    135    if (!IteratorHasRoomFor(*iter, sizeof(*result)))
    136      return ReadBytesInto(iter, result, sizeof(*result));
    137 
    138    iter->CopyInto(result);
    139 
    140    UpdateIter(iter, sizeof(*result));
    141    return true;
    142  }
    143 
    144  bool IgnoreSentinel(PickleIterator* iter) const
    145 #ifdef MOZ_PICKLE_SENTINEL_CHECKING
    146      ;
    147 #else
    148  {
    149    return true;
    150  }
    151 #endif
    152 
    153  // NOTE: The message type optional parameter should _only_ be called from
    154  // generated IPDL code, as it is used to trigger the IPC_READ_LATENCY_MS
    155  // telemetry probe.
    156  void EndRead(PickleIterator& iter, uint32_t ipcMessageType = 0) const;
    157 
    158  // Returns true if the given iterator has at least |len| bytes remaining it,
    159  // across all segments. If there is not that much data available, returns
    160  // false. Generally used when reading a (len, data) pair from the message,
    161  // before allocating |len| bytes of space, to ensure that reading |len| bytes
    162  // will succeed.
    163  bool HasBytesAvailable(const PickleIterator* iter, uint32_t len) const;
    164 
    165  // Truncate the message at the current point, discarding any data after this
    166  // point in the message.
    167  void Truncate(PickleIterator* iter);
    168 
    169  // Methods for adding to the payload of the Pickle.  These values are
    170  // appended to the end of the Pickle's payload.  When reading values from a
    171  // Pickle, it is important to read them in the order in which they were added
    172  // to the Pickle.
    173  bool WriteBytes(const void* data, uint32_t data_len);
    174 
    175  template <class T>
    176  bool WriteScalar(const T& value) {
    177    static_assert(std::is_arithmetic<T>::value);
    178    static_assert(!std::is_same<typename std::remove_cv<T>::type, bool>::value);
    179    return WriteBytes(&value, sizeof(value));
    180  }
    181 
    182  bool WriteBool(bool value);
    183  bool WriteInt16(int16_t value);
    184  bool WriteUInt16(uint16_t value);
    185  bool WriteInt(int value);
    186  bool WriteLong(long value);
    187  bool WriteULong(unsigned long value);
    188  bool WriteInt32(int32_t value);
    189  bool WriteUInt32(uint32_t value);
    190  bool WriteInt64(int64_t value);
    191  bool WriteUInt64(uint64_t value);
    192  bool WriteDouble(double value);
    193  bool WriteIntPtr(intptr_t value);
    194  bool WriteUnsignedChar(unsigned char value);
    195  bool WriteString(const std::string& value);
    196  bool WriteWString(const std::wstring& value);
    197  bool WriteData(const char* data, uint32_t length);
    198 
    199  // Takes ownership of data
    200  bool WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity);
    201 
    202  bool WriteSentinel(uint32_t sentinel)
    203 #ifdef MOZ_PICKLE_SENTINEL_CHECKING
    204      ;
    205 #else
    206  {
    207    return true;
    208  }
    209 #endif
    210 
    211  int32_t* GetInt32PtrForTest(uint32_t offset);
    212 
    213  void InputBytes(const char* data, uint32_t length);
    214 
    215  // Payload follows after allocation of Header (header size is customizable).
    216  struct Header {
    217    uint32_t payload_size;  // Specifies the size of the payload.
    218  };
    219  static_assert(std::has_unique_object_representations_v<Header>,
    220                "Header must not contain padding bytes");
    221 
    222  // Returns the header, cast to a user-specified type T.  The type T must be a
    223  // subclass of Header and its size must correspond to the header_size passed
    224  // to the Pickle constructor.
    225  template <class T>
    226  T* headerT() {
    227    DCHECK(sizeof(T) == header_size_);
    228    return static_cast<T*>(header_);
    229  }
    230  template <class T>
    231  const T* headerT() const {
    232    DCHECK(sizeof(T) == header_size_);
    233    return static_cast<const T*>(header_);
    234  }
    235 
    236  typedef uint32_t memberAlignmentType;
    237 
    238 protected:
    239  uint32_t payload_size() const { return header_->payload_size; }
    240 
    241  // Resizes the buffer for use when writing the specified amount of data. Call
    242  // EndWrite with the given length to pad out for the next write.
    243  void BeginWrite(uint32_t length);
    244 
    245  // Completes the write operation by padding the data with poison bytes. Should
    246  // be paired with BeginWrite, but it does not necessarily have to be called
    247  // after the data is written.
    248  void EndWrite(uint32_t length);
    249 
    250  // Round 'bytes' up to the next multiple of 'alignment'.  'alignment' must be
    251  // a power of 2.
    252  template <uint32_t alignment>
    253  struct ConstantAligner {
    254    static uint32_t align(int bytes) {
    255      static_assert((alignment & (alignment - 1)) == 0,
    256                    "alignment must be a power of two");
    257      return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1);
    258    }
    259  };
    260 
    261  static uint32_t AlignInt(int bytes) {
    262    return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes);
    263  }
    264 
    265  static uint32_t AlignCapacity(int bytes) {
    266    return ConstantAligner<kSegmentAlignment>::align(bytes);
    267  }
    268 
    269  // Returns true if the given iterator could point to data with the given
    270  // length. If there is no room for the given data before the end of the
    271  // payload, returns false.
    272  bool IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const;
    273 
    274  // Moves the iterator by the given number of bytes, making sure it is aligned.
    275  // Pointer (iterator) is NOT aligned, but the change in the pointer
    276  // is guaranteed to be a multiple of sizeof(memberAlignmentType).
    277  void UpdateIter(PickleIterator* iter, uint32_t bytes) const;
    278 
    279  // Figure out how big the message starting at range_start is. Returns 0 if
    280  // there's no enough data to determine (i.e., if [range_start, range_end) does
    281  // not contain enough of the message header to know the size).
    282  static uint32_t MessageSize(uint32_t header_size, const char* range_start,
    283                              const char* range_end);
    284 
    285  // Segments capacities are aligned to 8 bytes to ensure that all reads/writes
    286  // at 8-byte aligned offsets will be on 8-byte aligned pointers.
    287  static const uint32_t kSegmentAlignment = 8;
    288 
    289 private:
    290  friend class PickleIterator;
    291 
    292  BufferList buffers_;
    293  Header* header_;
    294  uint32_t header_size_;
    295 };
    296 
    297 #endif  // BASE_PICKLE_H__