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__