Line data Source code
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/Attributes.h"
17 : #include "mozilla/BufferList.h"
18 : #include "mozilla/mozalloc.h"
19 : #include "mozilla/TimeStamp.h"
20 :
21 : #ifdef FUZZING
22 : #include "base/singleton.h"
23 : #include "mozilla/ipc/Faulty.h"
24 : #endif
25 :
26 : #if !defined(RELEASE_OR_BETA) || defined(DEBUG)
27 : #define MOZ_PICKLE_SENTINEL_CHECKING
28 : #endif
29 :
30 : class Pickle;
31 :
32 : class PickleIterator {
33 : public:
34 : explicit PickleIterator(const Pickle& pickle);
35 :
36 : private:
37 : friend class Pickle;
38 :
39 : mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_;
40 : mozilla::TimeStamp start_;
41 :
42 : template<typename T>
43 : void CopyInto(T* dest);
44 : };
45 :
46 : // This class provides facilities for basic binary value packing and unpacking.
47 : //
48 : // The Pickle class supports appending primitive values (ints, strings, etc.)
49 : // to a pickle instance. The Pickle instance grows its internal memory buffer
50 : // dynamically to hold the sequence of primitive values. The internal memory
51 : // buffer is exposed as the "data" of the Pickle. This "data" can be passed
52 : // to a Pickle object to initialize it for reading.
53 : //
54 : // When reading from a Pickle object, it is important for the consumer to know
55 : // what value types to read and in what order to read them as the Pickle does
56 : // not keep track of the type of data written to it.
57 : //
58 : // The Pickle's data has a header which contains the size of the Pickle's
59 : // payload. It can optionally support additional space in the header. That
60 : // space is controlled by the header_size parameter passed to the Pickle
61 : // constructor.
62 : //
63 : class Pickle {
64 : public:
65 : ~Pickle();
66 :
67 : Pickle() = delete;
68 :
69 : // Initialize a Pickle object with the specified header size in bytes, which
70 : // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size
71 : // will be rounded up to ensure that the header size is 32bit-aligned.
72 : explicit Pickle(uint32_t header_size, size_t segment_capacity = 0);
73 :
74 : Pickle(uint32_t header_size, const char* data, uint32_t length);
75 :
76 : Pickle(const Pickle& other) = delete;
77 :
78 : Pickle(Pickle&& other);
79 :
80 : // Performs a deep copy.
81 : Pickle& operator=(const Pickle& other) = delete;
82 :
83 : Pickle& operator=(Pickle&& other);
84 :
85 : // Returns the size of the Pickle's data.
86 1312 : uint32_t size() const { return header_size_ + header_->payload_size; }
87 :
88 : typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
89 :
90 2293 : const BufferList& Buffers() const { return buffers_; }
91 :
92 838 : uint32_t CurrentSize() const { return buffers_.Size(); }
93 :
94 : // Methods for reading the payload of the Pickle. To read from the start of
95 : // the Pickle, initialize *iter to NULL. If successful, these methods return
96 : // true. Otherwise, false is returned to indicate that the result could not
97 : // be extracted.
98 : MOZ_MUST_USE bool ReadBool(PickleIterator* iter, bool* result) const;
99 : MOZ_MUST_USE bool ReadInt16(PickleIterator* iter, int16_t* result) const;
100 : MOZ_MUST_USE bool ReadUInt16(PickleIterator* iter, uint16_t* result) const;
101 : MOZ_MUST_USE bool ReadShort(PickleIterator* iter, short* result) const;
102 : MOZ_MUST_USE bool ReadInt(PickleIterator* iter, int* result) const;
103 : MOZ_MUST_USE bool ReadLong(PickleIterator* iter, long* result) const;
104 : MOZ_MUST_USE bool ReadULong(PickleIterator* iter, unsigned long* result) const;
105 : MOZ_MUST_USE bool ReadSize(PickleIterator* iter, size_t* result) const;
106 : MOZ_MUST_USE bool ReadInt32(PickleIterator* iter, int32_t* result) const;
107 : MOZ_MUST_USE bool ReadUInt32(PickleIterator* iter, uint32_t* result) const;
108 : MOZ_MUST_USE bool ReadInt64(PickleIterator* iter, int64_t* result) const;
109 : MOZ_MUST_USE bool ReadUInt64(PickleIterator* iter, uint64_t* result) const;
110 : MOZ_MUST_USE bool ReadDouble(PickleIterator* iter, double* result) const;
111 : MOZ_MUST_USE bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const;
112 : MOZ_MUST_USE bool ReadUnsignedChar(PickleIterator* iter, unsigned char* result) const;
113 : MOZ_MUST_USE bool ReadString(PickleIterator* iter, std::string* result) const;
114 : MOZ_MUST_USE bool ReadWString(PickleIterator* iter, std::wstring* result) const;
115 : MOZ_MUST_USE bool ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const;
116 : MOZ_MUST_USE bool ExtractBuffers(PickleIterator* iter, size_t length, BufferList* buffers,
117 : uint32_t alignment = sizeof(memberAlignmentType)) const;
118 :
119 : // Safer version of ReadInt() checks for the result not being negative.
120 : // Use it for reading the object sizes.
121 : MOZ_MUST_USE bool ReadLength(PickleIterator* iter, int* result) const;
122 :
123 : MOZ_MUST_USE bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const
124 : #ifdef MOZ_PICKLE_SENTINEL_CHECKING
125 : ;
126 : #else
127 : {
128 : return true;
129 : }
130 : #endif
131 :
132 : bool IgnoreSentinel(PickleIterator* iter) const
133 : #ifdef MOZ_PICKLE_SENTINEL_CHECKING
134 : ;
135 : #else
136 : {
137 : return true;
138 : }
139 : #endif
140 :
141 : // NOTE: The message type optional parameter should _only_ be called from
142 : // generated IPDL code, as it is used to trigger the IPC_READ_LATENCY_MS
143 : // telemetry probe.
144 : void EndRead(PickleIterator& iter, uint32_t ipcMessageType = 0) const;
145 :
146 : // Methods for adding to the payload of the Pickle. These values are
147 : // appended to the end of the Pickle's payload. When reading values from a
148 : // Pickle, it is important to read them in the order in which they were added
149 : // to the Pickle.
150 13778 : bool WriteBool(bool value) {
151 : #ifdef FUZZING
152 : Singleton<mozilla::ipc::Faulty>::get()->FuzzBool(&value);
153 : #endif
154 13778 : return WriteInt(value ? 1 : 0);
155 : }
156 19 : bool WriteInt16(int16_t value) {
157 : #ifdef FUZZING
158 : Singleton<mozilla::ipc::Faulty>::get()->FuzzInt16(&value);
159 : #endif
160 19 : return WriteBytes(&value, sizeof(value));
161 : }
162 29 : bool WriteUInt16(uint16_t value) {
163 : #ifdef FUZZING
164 : Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt16(&value);
165 : #endif
166 29 : return WriteBytes(&value, sizeof(value));
167 : }
168 41570 : bool WriteInt(int value) {
169 : #ifdef FUZZING
170 : Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
171 : #endif
172 41570 : return WriteBytes(&value, sizeof(value));
173 : }
174 : bool WriteLong(long value) {
175 : // Always written as a 64-bit value since the size for this type can
176 : // differ between architectures.
177 : #ifdef FUZZING
178 : Singleton<mozilla::ipc::Faulty>::get()->FuzzLong(&value);
179 : #endif
180 : return WriteInt64(int64_t(value));
181 : }
182 0 : bool WriteULong(unsigned long value) {
183 : // Always written as a 64-bit value since the size for this type can
184 : // differ between architectures.
185 : #ifdef FUZZING
186 : Singleton<mozilla::ipc::Faulty>::get()->FuzzULong(&value);
187 : #endif
188 0 : return WriteUInt64(uint64_t(value));
189 : }
190 1645 : bool WriteSize(size_t value) {
191 : // Always written as a 64-bit value since the size for this type can
192 : // differ between architectures.
193 : #ifdef FUZZING
194 : Singleton<mozilla::ipc::Faulty>::get()->FuzzSize(&value);
195 : #endif
196 1645 : return WriteUInt64(uint64_t(value));
197 : }
198 : bool WriteInt32(int32_t value) {
199 : #ifdef FUZZING
200 : Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
201 : #endif
202 : return WriteBytes(&value, sizeof(value));
203 : }
204 83752 : bool WriteUInt32(uint32_t value) {
205 : #ifdef FUZZING
206 : Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt32(&value);
207 : #endif
208 83752 : return WriteBytes(&value, sizeof(value));
209 : }
210 11 : bool WriteInt64(int64_t value) {
211 : #ifdef FUZZING
212 : Singleton<mozilla::ipc::Faulty>::get()->FuzzInt64(&value);
213 : #endif
214 11 : return WriteBytes(&value, sizeof(value));
215 : }
216 1645 : bool WriteUInt64(uint64_t value) {
217 : #ifdef FUZZING
218 : Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt64(&value);
219 : #endif
220 1645 : return WriteBytes(&value, sizeof(value));
221 : }
222 2 : bool WriteDouble(double value) {
223 : #ifdef FUZZING
224 : Singleton<mozilla::ipc::Faulty>::get()->FuzzDouble(&value);
225 : #endif
226 2 : return WriteBytes(&value, sizeof(value));
227 : }
228 : bool WriteIntPtr(intptr_t value) {
229 : // Always written as a 64-bit value since the size for this type can
230 : // differ between architectures.
231 : return WriteInt64(int64_t(value));
232 : }
233 : bool WriteUnsignedChar(unsigned char value) {
234 : #ifdef FUZZING
235 : Singleton<mozilla::ipc::Faulty>::get()->FuzzUChar(&value);
236 : #endif
237 : return WriteBytes(&value, sizeof(value));
238 : }
239 : bool WriteString(const std::string& value);
240 : bool WriteWString(const std::wstring& value);
241 : bool WriteData(const char* data, uint32_t length);
242 : bool WriteBytes(const void* data, uint32_t data_len,
243 : uint32_t alignment = sizeof(memberAlignmentType));
244 :
245 : bool WriteSentinel(uint32_t sentinel)
246 : #ifdef MOZ_PICKLE_SENTINEL_CHECKING
247 : ;
248 : #else
249 : {
250 : return true;
251 : }
252 : #endif
253 :
254 : int32_t* GetInt32PtrForTest(uint32_t offset);
255 :
256 : void InputBytes(const char* data, uint32_t length);
257 :
258 : // Payload follows after allocation of Header (header size is customizable).
259 : struct Header {
260 : uint32_t payload_size; // Specifies the size of the payload.
261 : };
262 :
263 : // Returns the header, cast to a user-specified type T. The type T must be a
264 : // subclass of Header and its size must correspond to the header_size passed
265 : // to the Pickle constructor.
266 : template <class T>
267 4637 : T* headerT() {
268 4637 : DCHECK(sizeof(T) == header_size_);
269 4637 : return static_cast<T*>(header_);
270 : }
271 : template <class T>
272 20777 : const T* headerT() const {
273 20777 : DCHECK(sizeof(T) == header_size_);
274 20777 : return static_cast<const T*>(header_);
275 : }
276 :
277 : typedef uint32_t memberAlignmentType;
278 :
279 : protected:
280 : uint32_t payload_size() const { return header_->payload_size; }
281 :
282 : // Resizes the buffer for use when writing the specified amount of data. The
283 : // location that the data should be written at is returned, or NULL if there
284 : // was an error. Call EndWrite with the returned offset and the given length
285 : // to pad out for the next write.
286 : void BeginWrite(uint32_t length, uint32_t alignment);
287 :
288 : // Completes the write operation by padding the data with NULL bytes until it
289 : // is padded. Should be paired with BeginWrite, but it does not necessarily
290 : // have to be called after the data is written.
291 : void EndWrite(uint32_t length);
292 :
293 : // Round 'bytes' up to the next multiple of 'alignment'. 'alignment' must be
294 : // a power of 2.
295 : template<uint32_t alignment> struct ConstantAligner {
296 692435 : static uint32_t align(int bytes) {
297 : static_assert((alignment & (alignment - 1)) == 0,
298 : "alignment must be a power of two");
299 692435 : return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1);
300 : }
301 : };
302 :
303 692010 : static uint32_t AlignInt(int bytes) {
304 692010 : return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes);
305 : }
306 :
307 388 : static uint32_t AlignCapacity(int bytes) {
308 388 : return ConstantAligner<kSegmentAlignment>::align(bytes);
309 : }
310 :
311 : // Returns true if the given iterator could point to data with the given
312 : // length. If there is no room for the given data before the end of the
313 : // payload, returns false.
314 : bool IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const;
315 :
316 : // Moves the iterator by the given number of bytes, making sure it is aligned.
317 : // Pointer (iterator) is NOT aligned, but the change in the pointer
318 : // is guaranteed to be a multiple of sizeof(memberAlignmentType).
319 : void UpdateIter(PickleIterator* iter, uint32_t bytes) const;
320 :
321 : // Figure out how big the message starting at range_start is. Returns 0 if
322 : // there's no enough data to determine (i.e., if [range_start, range_end) does
323 : // not contain enough of the message header to know the size).
324 : static uint32_t MessageSize(uint32_t header_size,
325 : const char* range_start,
326 : const char* range_end);
327 :
328 : // Segments capacities are aligned to 8 bytes to ensure that all reads/writes
329 : // at 8-byte aligned offsets will be on 8-byte aligned pointers.
330 : static const uint32_t kSegmentAlignment = 8;
331 :
332 : private:
333 : friend class PickleIterator;
334 :
335 : BufferList buffers_;
336 : Header* header_;
337 : uint32_t header_size_;
338 : };
339 :
340 : #endif // BASE_PICKLE_H__
|