pickle.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/pickle.h"
  5. #include <algorithm> // for max()
  6. #include <cstdlib>
  7. #include <limits>
  8. #include "base/bits.h"
  9. #include "base/numerics/safe_conversions.h"
  10. #include "base/numerics/safe_math.h"
  11. #include "build/build_config.h"
  12. namespace base {
  13. // static
  14. const size_t Pickle::kPayloadUnit = 64;
  15. static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
  16. PickleIterator::PickleIterator(const Pickle& pickle)
  17. : payload_(pickle.payload()),
  18. read_index_(0),
  19. end_index_(pickle.payload_size()) {}
  20. template <typename Type>
  21. inline bool PickleIterator::ReadBuiltinType(Type* result) {
  22. const char* read_from = GetReadPointerAndAdvance<Type>();
  23. if (!read_from)
  24. return false;
  25. if (sizeof(Type) > sizeof(uint32_t))
  26. memcpy(result, read_from, sizeof(*result));
  27. else
  28. *result = *reinterpret_cast<const Type*>(read_from);
  29. return true;
  30. }
  31. inline void PickleIterator::Advance(size_t size) {
  32. size_t aligned_size = bits::AlignUp(size, sizeof(uint32_t));
  33. if (end_index_ - read_index_ < aligned_size) {
  34. read_index_ = end_index_;
  35. } else {
  36. read_index_ += aligned_size;
  37. }
  38. }
  39. template <typename Type>
  40. inline const char* PickleIterator::GetReadPointerAndAdvance() {
  41. if (sizeof(Type) > end_index_ - read_index_) {
  42. read_index_ = end_index_;
  43. return nullptr;
  44. }
  45. const char* current_read_ptr = payload_ + read_index_;
  46. Advance(sizeof(Type));
  47. return current_read_ptr;
  48. }
  49. const char* PickleIterator::GetReadPointerAndAdvance(size_t num_bytes) {
  50. if (num_bytes > end_index_ - read_index_) {
  51. read_index_ = end_index_;
  52. return nullptr;
  53. }
  54. const char* current_read_ptr = payload_ + read_index_;
  55. Advance(num_bytes);
  56. return current_read_ptr;
  57. }
  58. inline const char* PickleIterator::GetReadPointerAndAdvance(
  59. size_t num_elements,
  60. size_t size_element) {
  61. // Check for size_t overflow.
  62. size_t num_bytes;
  63. if (!CheckMul(num_elements, size_element).AssignIfValid(&num_bytes))
  64. return nullptr;
  65. return GetReadPointerAndAdvance(num_bytes);
  66. }
  67. bool PickleIterator::ReadBool(bool* result) {
  68. return ReadBuiltinType(result);
  69. }
  70. bool PickleIterator::ReadInt(int* result) {
  71. return ReadBuiltinType(result);
  72. }
  73. bool PickleIterator::ReadLong(long* result) {
  74. // Always read long as a 64-bit value to ensure compatibility between 32-bit
  75. // and 64-bit processes.
  76. int64_t result_int64 = 0;
  77. if (!ReadBuiltinType(&result_int64))
  78. return false;
  79. // CHECK if the cast truncates the value so that we know to change this IPC
  80. // parameter to use int64_t.
  81. *result = base::checked_cast<long>(result_int64);
  82. return true;
  83. }
  84. bool PickleIterator::ReadUInt16(uint16_t* result) {
  85. return ReadBuiltinType(result);
  86. }
  87. bool PickleIterator::ReadUInt32(uint32_t* result) {
  88. return ReadBuiltinType(result);
  89. }
  90. bool PickleIterator::ReadInt64(int64_t* result) {
  91. return ReadBuiltinType(result);
  92. }
  93. bool PickleIterator::ReadUInt64(uint64_t* result) {
  94. return ReadBuiltinType(result);
  95. }
  96. bool PickleIterator::ReadFloat(float* result) {
  97. // crbug.com/315213
  98. // The source data may not be properly aligned, and unaligned float reads
  99. // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
  100. // into the result.
  101. const char* read_from = GetReadPointerAndAdvance<float>();
  102. if (!read_from)
  103. return false;
  104. memcpy(result, read_from, sizeof(*result));
  105. return true;
  106. }
  107. bool PickleIterator::ReadDouble(double* result) {
  108. // crbug.com/315213
  109. // The source data may not be properly aligned, and unaligned double reads
  110. // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
  111. // into the result.
  112. const char* read_from = GetReadPointerAndAdvance<double>();
  113. if (!read_from)
  114. return false;
  115. memcpy(result, read_from, sizeof(*result));
  116. return true;
  117. }
  118. bool PickleIterator::ReadString(std::string* result) {
  119. size_t len;
  120. if (!ReadLength(&len))
  121. return false;
  122. const char* read_from = GetReadPointerAndAdvance(len);
  123. if (!read_from)
  124. return false;
  125. result->assign(read_from, len);
  126. return true;
  127. }
  128. bool PickleIterator::ReadStringPiece(StringPiece* result) {
  129. size_t len;
  130. if (!ReadLength(&len))
  131. return false;
  132. const char* read_from = GetReadPointerAndAdvance(len);
  133. if (!read_from)
  134. return false;
  135. *result = StringPiece(read_from, len);
  136. return true;
  137. }
  138. bool PickleIterator::ReadString16(std::u16string* result) {
  139. size_t len;
  140. if (!ReadLength(&len))
  141. return false;
  142. const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16_t));
  143. if (!read_from)
  144. return false;
  145. result->assign(reinterpret_cast<const char16_t*>(read_from), len);
  146. return true;
  147. }
  148. bool PickleIterator::ReadStringPiece16(StringPiece16* result) {
  149. size_t len;
  150. if (!ReadLength(&len))
  151. return false;
  152. const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16_t));
  153. if (!read_from)
  154. return false;
  155. *result = StringPiece16(reinterpret_cast<const char16_t*>(read_from), len);
  156. return true;
  157. }
  158. bool PickleIterator::ReadData(const char** data, size_t* length) {
  159. *length = 0;
  160. *data = nullptr;
  161. if (!ReadLength(length))
  162. return false;
  163. return ReadBytes(data, *length);
  164. }
  165. bool PickleIterator::ReadData(base::span<const uint8_t>* data) {
  166. const char* ptr;
  167. size_t length;
  168. if (!ReadData(&ptr, &length))
  169. return false;
  170. *data = base::as_bytes(base::make_span(ptr, length));
  171. return true;
  172. }
  173. bool PickleIterator::ReadBytes(const char** data, size_t length) {
  174. const char* read_from = GetReadPointerAndAdvance(length);
  175. if (!read_from)
  176. return false;
  177. *data = read_from;
  178. return true;
  179. }
  180. Pickle::Attachment::Attachment() = default;
  181. Pickle::Attachment::~Attachment() = default;
  182. // Payload is uint32_t aligned.
  183. Pickle::Pickle()
  184. : header_(nullptr),
  185. header_size_(sizeof(Header)),
  186. capacity_after_header_(0),
  187. write_offset_(0) {
  188. static_assert(base::bits::IsPowerOfTwo(Pickle::kPayloadUnit),
  189. "Pickle::kPayloadUnit must be a power of two");
  190. Resize(kPayloadUnit);
  191. header_->payload_size = 0;
  192. }
  193. Pickle::Pickle(size_t header_size)
  194. : header_(nullptr),
  195. header_size_(bits::AlignUp(header_size, sizeof(uint32_t))),
  196. capacity_after_header_(0),
  197. write_offset_(0) {
  198. DCHECK_GE(header_size, sizeof(Header));
  199. DCHECK_LE(header_size, kPayloadUnit);
  200. Resize(kPayloadUnit);
  201. header_->payload_size = 0;
  202. }
  203. Pickle::Pickle(const char* data, size_t data_len)
  204. : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
  205. header_size_(0),
  206. capacity_after_header_(kCapacityReadOnly),
  207. write_offset_(0) {
  208. if (data_len >= sizeof(Header))
  209. header_size_ = data_len - header_->payload_size;
  210. if (header_size_ > data_len)
  211. header_size_ = 0;
  212. if (header_size_ != bits::AlignUp(header_size_, sizeof(uint32_t)))
  213. header_size_ = 0;
  214. // If there is anything wrong with the data, we're not going to use it.
  215. if (!header_size_)
  216. header_ = nullptr;
  217. }
  218. Pickle::Pickle(const Pickle& other)
  219. : header_(nullptr),
  220. header_size_(other.header_size_),
  221. capacity_after_header_(0),
  222. write_offset_(other.write_offset_) {
  223. if (other.header_) {
  224. Resize(other.header_->payload_size);
  225. memcpy(header_, other.header_, header_size_ + other.header_->payload_size);
  226. }
  227. }
  228. Pickle::~Pickle() {
  229. if (capacity_after_header_ != kCapacityReadOnly)
  230. free(header_);
  231. }
  232. Pickle& Pickle::operator=(const Pickle& other) {
  233. if (this == &other) {
  234. return *this;
  235. }
  236. if (capacity_after_header_ == kCapacityReadOnly) {
  237. header_ = nullptr;
  238. capacity_after_header_ = 0;
  239. }
  240. if (header_size_ != other.header_size_) {
  241. free(header_);
  242. header_ = nullptr;
  243. header_size_ = other.header_size_;
  244. }
  245. if (other.header_) {
  246. Resize(other.header_->payload_size);
  247. memcpy(header_, other.header_,
  248. other.header_size_ + other.header_->payload_size);
  249. write_offset_ = other.write_offset_;
  250. }
  251. return *this;
  252. }
  253. void Pickle::WriteString(const StringPiece& value) {
  254. WriteData(value.data(), value.size());
  255. }
  256. void Pickle::WriteString16(const StringPiece16& value) {
  257. WriteInt(checked_cast<int>(value.size()));
  258. WriteBytes(value.data(), value.size() * sizeof(char16_t));
  259. }
  260. void Pickle::WriteData(const char* data, size_t length) {
  261. WriteInt(checked_cast<int>(length));
  262. WriteBytes(data, length);
  263. }
  264. void Pickle::WriteBytes(const void* data, size_t length) {
  265. WriteBytesCommon(data, length);
  266. }
  267. void Pickle::Reserve(size_t length) {
  268. size_t data_len = bits::AlignUp(length, sizeof(uint32_t));
  269. DCHECK_GE(data_len, length);
  270. #ifdef ARCH_CPU_64_BITS
  271. DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
  272. #endif
  273. DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
  274. size_t new_size = write_offset_ + data_len;
  275. if (new_size > capacity_after_header_)
  276. Resize(capacity_after_header_ * 2 + new_size);
  277. }
  278. bool Pickle::WriteAttachment(scoped_refptr<Attachment> attachment) {
  279. return false;
  280. }
  281. bool Pickle::ReadAttachment(base::PickleIterator* iter,
  282. scoped_refptr<Attachment>* attachment) const {
  283. return false;
  284. }
  285. bool Pickle::HasAttachments() const {
  286. return false;
  287. }
  288. void Pickle::Resize(size_t new_capacity) {
  289. CHECK_NE(capacity_after_header_, kCapacityReadOnly);
  290. capacity_after_header_ = bits::AlignUp(new_capacity, kPayloadUnit);
  291. void* p = realloc(header_, GetTotalAllocatedSize());
  292. CHECK(p);
  293. header_ = reinterpret_cast<Header*>(p);
  294. }
  295. void* Pickle::ClaimBytes(size_t num_bytes) {
  296. void* p = ClaimUninitializedBytesInternal(num_bytes);
  297. CHECK(p);
  298. memset(p, 0, num_bytes);
  299. return p;
  300. }
  301. size_t Pickle::GetTotalAllocatedSize() const {
  302. if (capacity_after_header_ == kCapacityReadOnly)
  303. return 0;
  304. return header_size_ + capacity_after_header_;
  305. }
  306. // static
  307. const char* Pickle::FindNext(size_t header_size,
  308. const char* start,
  309. const char* end) {
  310. size_t pickle_size = 0;
  311. if (!PeekNext(header_size, start, end, &pickle_size))
  312. return nullptr;
  313. if (pickle_size > static_cast<size_t>(end - start))
  314. return nullptr;
  315. return start + pickle_size;
  316. }
  317. // static
  318. bool Pickle::PeekNext(size_t header_size,
  319. const char* start,
  320. const char* end,
  321. size_t* pickle_size) {
  322. DCHECK_EQ(header_size, bits::AlignUp(header_size, sizeof(uint32_t)));
  323. DCHECK_GE(header_size, sizeof(Header));
  324. DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
  325. size_t length = static_cast<size_t>(end - start);
  326. if (length < sizeof(Header))
  327. return false;
  328. const Header* hdr = reinterpret_cast<const Header*>(start);
  329. if (length < header_size)
  330. return false;
  331. // If payload_size causes an overflow, we return maximum possible
  332. // pickle size to indicate that.
  333. *pickle_size = ClampAdd(header_size, hdr->payload_size);
  334. return true;
  335. }
  336. template <size_t length>
  337. void Pickle::WriteBytesStatic(const void* data) {
  338. WriteBytesCommon(data, length);
  339. }
  340. template void Pickle::WriteBytesStatic<2>(const void* data);
  341. template void Pickle::WriteBytesStatic<4>(const void* data);
  342. template void Pickle::WriteBytesStatic<8>(const void* data);
  343. inline void* Pickle::ClaimUninitializedBytesInternal(size_t length) {
  344. DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
  345. << "oops: pickle is readonly";
  346. size_t data_len = bits::AlignUp(length, sizeof(uint32_t));
  347. DCHECK_GE(data_len, length);
  348. #ifdef ARCH_CPU_64_BITS
  349. DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
  350. #endif
  351. DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
  352. size_t new_size = write_offset_ + data_len;
  353. if (new_size > capacity_after_header_) {
  354. size_t new_capacity = capacity_after_header_ * 2;
  355. const size_t kPickleHeapAlign = 4096;
  356. if (new_capacity > kPickleHeapAlign) {
  357. new_capacity =
  358. bits::AlignUp(new_capacity, kPickleHeapAlign) - kPayloadUnit;
  359. }
  360. Resize(std::max(new_capacity, new_size));
  361. }
  362. char* write = mutable_payload() + write_offset_;
  363. memset(write + length, 0, data_len - length); // Always initialize padding
  364. header_->payload_size = static_cast<uint32_t>(new_size);
  365. write_offset_ = new_size;
  366. return write;
  367. }
  368. inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
  369. DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
  370. << "oops: pickle is readonly";
  371. MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
  372. void* write = ClaimUninitializedBytesInternal(length);
  373. memcpy(write, data, length);
  374. }
  375. } // namespace base