Monero
portable_storage_from_bin.h
Go to the documentation of this file.
1 // Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name of the Andrey N. Sabelnikov nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 //
26 
27 
28 
29 #pragma once
30 
31 #include "misc_language.h"
32 #include "misc_log_ex.h"
33 #include "portable_storage_base.h"
35 
36 #undef MONERO_DEFAULT_LOG_CATEGORY
37 #define MONERO_DEFAULT_LOG_CATEGORY "serialization"
38 
39 #ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
40 #define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
41 #else
42 #define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL 100
43 #endif
44 
45 namespace epee
46 {
47  namespace serialization
48  {
49  template<typename T>
50  struct ps_min_bytes {
51  static constexpr const size_t strict = 4096; // actual low bound
52  };
53  template<> struct ps_min_bytes<uint64_t> { static constexpr const size_t strict = 8; };
54  template<> struct ps_min_bytes<int64_t> { static constexpr const size_t strict = 8; };
55  template<> struct ps_min_bytes<uint32_t> { static constexpr const size_t strict = 4; };
56  template<> struct ps_min_bytes<int32_t> { static constexpr const size_t strict = 4; };
57  template<> struct ps_min_bytes<uint16_t> { static constexpr const size_t strict = 2; };
58  template<> struct ps_min_bytes<int16_t> { static constexpr const size_t strict = 2; };
59  template<> struct ps_min_bytes<uint8_t> { static constexpr const size_t strict = 1; };
60  template<> struct ps_min_bytes<int8_t> { static constexpr const size_t strict = 1; };
61  template<> struct ps_min_bytes<double> { static constexpr const size_t strict = 8; };
62  template<> struct ps_min_bytes<bool> { static constexpr const size_t strict = 1; };
63  template<> struct ps_min_bytes<std::string> { static constexpr const size_t strict = 2; };
64  template<> struct ps_min_bytes<section> { static constexpr const size_t strict = 1; };
65  template<> struct ps_min_bytes<array_entry> { static constexpr const size_t strict = 1; };
66 
68  {
69  throwable_buffer_reader(const void* ptr, size_t sz);
70  void read(void* target, size_t count);
71  void read_sec_name(std::string& sce_name);
72  template<class t_pod_type>
73  void read(t_pod_type& pod_val);
74  template<class t_type>
75  t_type read();
76  template<class type_name>
79  size_t read_varint();
80  template<class t_type>
83  void read(section& sec);
84  void read(std::string& str);
85  void read(array_entry &ae);
86  template<class t_type>
87  size_t min_bytes() const;
88  void set_limits(size_t objects, size_t fields, size_t strings);
89  private:
91  {
92  size_t& m_counter_ref;
93  recursuion_limitation_guard(size_t& counter):m_counter_ref(counter)
94  {
95  ++m_counter_ref;
96  CHECK_AND_ASSERT_THROW_MES(m_counter_ref < EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL, "Wrong blob data in portable storage: recursion limitation (" << EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL << ") exceeded");
97  }
99  {
100  CHECK_AND_ASSERT_THROW_MES(m_counter_ref != 0, "Internal error: m_counter_ref == 0 while ~recursuion_limitation_guard()");
101  --m_counter_ref;
102  }
103  };
104 #define RECURSION_LIMITATION() recursuion_limitation_guard rl(m_recursion_count)
105 
106  const uint8_t* m_ptr;
107  size_t m_count;
109  size_t m_objects;
110  size_t m_fields;
111  size_t m_strings;
112 
113  size_t max_objects;
114  size_t max_fields;
115  size_t max_strings;
116  };
117 
118  inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz)
119  {
120  if(!ptr)
121  throw std::runtime_error("throwable_buffer_reader: ptr==nullptr");
122  if(!sz)
123  throw std::runtime_error("throwable_buffer_reader: sz==0");
124  m_ptr = (uint8_t*)ptr;
125  m_count = sz;
126  m_recursion_count = 0;
127  m_objects = 0;
128  m_fields = 0;
129  m_strings = 0;
130  max_objects = std::numeric_limits<size_t>::max();
131  max_fields = std::numeric_limits<size_t>::max();
132  max_strings = std::numeric_limits<size_t>::max();
133  }
134  inline
135  void throwable_buffer_reader::read(void* target, size_t count)
136  {
138  CHECK_AND_ASSERT_THROW_MES(m_count >= count, " attempt to read " << count << " bytes from buffer with " << m_count << " bytes remained");
139  memcpy(target, m_ptr, count);
140  m_ptr += count;
141  m_count -= count;
142  }
143  inline
145  {
147  uint8_t name_len = 0;
148  read(name_len);
149  CHECK_AND_ASSERT_THROW_MES(name_len > 0, "Section name is missing");
150  sce_name.resize(name_len);
151  read((void*)sce_name.data(), name_len);
152  }
153 
154  template<class t_pod_type>
155  void throwable_buffer_reader::read(t_pod_type& pod_val)
156  {
158  static_assert(std::is_pod<t_pod_type>::value, "POD type expected");
159  read(&pod_val, sizeof(pod_val));
160  pod_val = CONVERT_POD(pod_val);
161  }
162 
163  template<>
164  void throwable_buffer_reader::read<bool>(bool& pod_val)
165  {
167  static_assert(std::is_pod<bool>::value, "POD type expected");
168  static_assert(sizeof(bool) == sizeof(uint8_t), "We really shouldn't use bool directly in serialization code. Replace it with uint8_t if this assert triggers!");
169  uint8_t t;
170  read(&t, sizeof(t));
171  CHECK_AND_ASSERT_THROW_MES(t <= 1, "Invalid bool value " << t);
172  pod_val = (t != 0);
173  }
174 
175  template<class t_type>
177  {
179  t_type v;
180  read(v);
181  return v;
182  }
183 
184 
185  template<class type_name>
187  {
189  //for pod types
191  size_t size = read_varint();
192  CHECK_AND_ASSERT_THROW_MES(size <= m_count / ps_min_bytes<type_name>::strict, "Size sanity check failed");
193  if (std::is_same<type_name, section>())
194  {
195  CHECK_AND_ASSERT_THROW_MES(size <= max_objects - m_objects, "Too many objects");
196  m_objects += size;
197  }
198  else if (std::is_same<type_name, std::string>())
199  {
200  CHECK_AND_ASSERT_THROW_MES(size <= max_strings - m_strings, "Too many strings");
201  m_strings += size;
202  }
203 
204  sa.reserve(size);
205  //TODO: add some optimization here later
206  while(size--)
207  sa.m_array.push_back(read<type_name>());
208  return storage_entry(array_entry(std::move(sa)));
209  }
210 
211  inline
213  {
216  switch(type)
217  {
218  case SERIALIZE_TYPE_INT64: return read_ae<int64_t>();
219  case SERIALIZE_TYPE_INT32: return read_ae<int32_t>();
220  case SERIALIZE_TYPE_INT16: return read_ae<int16_t>();
221  case SERIALIZE_TYPE_INT8: return read_ae<int8_t>();
222  case SERIALIZE_TYPE_UINT64: return read_ae<uint64_t>();
223  case SERIALIZE_TYPE_UINT32: return read_ae<uint32_t>();
224  case SERIALIZE_TYPE_UINT16: return read_ae<uint16_t>();
225  case SERIALIZE_TYPE_UINT8: return read_ae<uint8_t>();
226  case SERIALIZE_TYPE_DOUBLE: return read_ae<double>();
227  case SERIALIZE_TYPE_BOOL: return read_ae<bool>();
228  case SERIALIZE_TYPE_STRING: return read_ae<std::string>();
229  case SERIALIZE_TYPE_OBJECT: return read_ae<section>();
230  case SERIALIZE_TYPE_ARRAY: return read_ae<array_entry>();
231  default:
232  CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << type);
233  }
234  }
235 
236  inline
238  {
240  CHECK_AND_ASSERT_THROW_MES(m_count >= 1, "empty buff, expected place for varint");
241  size_t v = 0;
243  switch (size_mask)
244  {
245  case PORTABLE_RAW_SIZE_MARK_BYTE: v = read<uint8_t>();break;
246  case PORTABLE_RAW_SIZE_MARK_WORD: v = read<uint16_t>();break;
247  case PORTABLE_RAW_SIZE_MARK_DWORD: v = read<uint32_t>();break;
248  case PORTABLE_RAW_SIZE_MARK_INT64: v = read<uint64_t>();break;
249  default:
250  CHECK_AND_ASSERT_THROW_MES(false, "unknown varint size_mask = " << size_mask);
251  }
252  v >>= 2;
253  return v;
254  }
255 
256  template<class t_type>
258  {
260  t_type v;
261  read(v);
262  return storage_entry(v);
263  }
264 
265  template<>
266  inline storage_entry throwable_buffer_reader::read_se<std::string>()
267  {
269  CHECK_AND_ASSERT_THROW_MES(m_strings + 1 <= max_strings, "Too many strings");
270  m_strings += 1;
271  return storage_entry(read<std::string>());
272  }
273 
274 
275  template<>
276  inline storage_entry throwable_buffer_reader::read_se<section>()
277  {
279  CHECK_AND_ASSERT_THROW_MES(m_objects < max_objects, "Too many objects");
280  ++m_objects;
281  section s;//use extra variable due to vs bug, line "storage_entry se(section()); " can't be compiled in visual studio
283  section& section_entry = boost::get<section>(se);
284  read(section_entry);
285  return se;
286  }
287 
288  template<>
289  inline storage_entry throwable_buffer_reader::read_se<array_entry>()
290  {
292  uint8_t ent_type = 0;
293  read(ent_type);
294  CHECK_AND_ASSERT_THROW_MES(ent_type&SERIALIZE_FLAG_ARRAY, "wrong type sequenses");
295  return load_storage_array_entry(ent_type);
296  }
297 
298  inline
300  {
302  uint8_t ent_type = 0;
303  read(ent_type);
304  if(ent_type&SERIALIZE_FLAG_ARRAY)
305  return load_storage_array_entry(ent_type);
306 
307  switch(ent_type)
308  {
309  case SERIALIZE_TYPE_INT64: return read_se<int64_t>();
310  case SERIALIZE_TYPE_INT32: return read_se<int32_t>();
311  case SERIALIZE_TYPE_INT16: return read_se<int16_t>();
312  case SERIALIZE_TYPE_INT8: return read_se<int8_t>();
313  case SERIALIZE_TYPE_UINT64: return read_se<uint64_t>();
314  case SERIALIZE_TYPE_UINT32: return read_se<uint32_t>();
315  case SERIALIZE_TYPE_UINT16: return read_se<uint16_t>();
316  case SERIALIZE_TYPE_UINT8: return read_se<uint8_t>();
317  case SERIALIZE_TYPE_DOUBLE: return read_se<double>();
318  case SERIALIZE_TYPE_BOOL: return read_se<bool>();
319  case SERIALIZE_TYPE_STRING: return read_se<std::string>();
320  case SERIALIZE_TYPE_OBJECT: return read_se<section>();
321  case SERIALIZE_TYPE_ARRAY: return read_se<array_entry>();
322  default:
323  CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << ent_type);
324  }
325  }
326  inline
328  {
330  sec.m_entries.clear();
331  size_t count = read_varint();
332  CHECK_AND_ASSERT_THROW_MES(count <= max_fields - m_fields, "Too many object fields");
333  m_fields += count;
334  while(count--)
335  {
336  //read section name string
337  std::string sec_name;
338  read_sec_name(sec_name);
339  const auto insert_loc = sec.m_entries.lower_bound(sec_name);
340  CHECK_AND_ASSERT_THROW_MES(insert_loc == sec.m_entries.end() || insert_loc->first != sec_name, "duplicate key: " << sec_name);
341  sec.m_entries.emplace_hint(insert_loc, std::move(sec_name), load_storage_entry());
342  }
343  }
344  inline
346  {
348  size_t len = read_varint();
349  CHECK_AND_ASSERT_THROW_MES(len < MAX_STRING_LEN_POSSIBLE, "to big string len value in storage: " << len);
350  CHECK_AND_ASSERT_THROW_MES(m_count >= len, "string len count value " << len << " goes out of remain storage len " << m_count);
351  //do this manually to avoid double memory write in huge strings (first time at resize, second at read)
352  str.assign((const char*)m_ptr, len);
353  m_ptr+=len;
354  m_count -= len;
355  }
356  inline
358  {
360  CHECK_AND_ASSERT_THROW_MES(false, "Reading array entry is not supported");
361  }
362  inline
363  void throwable_buffer_reader::set_limits(size_t objects, size_t fields, size_t strings)
364  {
365  max_objects = objects;
366  max_fields = fields;
367  max_strings = strings;
368  }
369  }
370 }
Definition: binary_utils.h:36
recursuion_limitation_guard(size_t &counter)
Definition: portable_storage_from_bin.h:93
storage_entry load_storage_entry()
Definition: portable_storage_from_bin.h:299
size_t max_strings
Definition: portable_storage_from_bin.h:115
storage_entry read_ae()
Definition: portable_storage_from_bin.h:186
const uint8_t * m_ptr
Definition: portable_storage_from_bin.h:106
int * count
Definition: gmock_stress_test.cc:176
#define PORTABLE_RAW_SIZE_MARK_BYTE
Definition: portable_storage_base.h:42
::std::string string
Definition: gtest-port.h:1097
t
Definition: console.py:33
#define PORTABLE_RAW_SIZE_MARK_WORD
Definition: portable_storage_base.h:43
storage_entry load_storage_array_entry(uint8_t type)
Definition: portable_storage_from_bin.h:212
#define SERIALIZE_TYPE_INT32
Definition: portable_storage_base.h:53
void reserve(size_t n)
Definition: portable_storage_base.h:134
#define SERIALIZE_TYPE_INT16
Definition: portable_storage_base.h:54
size_t m_objects
Definition: portable_storage_from_bin.h:109
int type
Definition: superscalar.cpp:50
const char * s
Definition: minissdp.c:596
Definition: enums.h:67
boost::variant< uint64_t, uint32_t, uint16_t, uint8_t, int64_t, int32_t, int16_t, int8_t, double, bool, std::string, section, array_entry > storage_entry
Definition: portable_storage_base.h:161
unsigned short uint16_t
Definition: stdint.h:125
#define MAX_STRING_LEN_POSSIBLE
Definition: portable_storage_base.h:48
unsigned char uint8_t
Definition: stdint.h:124
#define SERIALIZE_TYPE_STRING
Definition: portable_storage_base.h:61
#define SERIALIZE_TYPE_INT64
Definition: portable_storage_base.h:52
#define CONVERT_POD(x)
Definition: portable_storage_bin_utils.h:43
Definition: portable_storage_base.h:82
#define SERIALIZE_TYPE_OBJECT
Definition: portable_storage_base.h:63
#define SERIALIZE_TYPE_UINT32
Definition: portable_storage_base.h:57
#define SERIALIZE_TYPE_UINT64
Definition: portable_storage_base.h:56
size_t read_varint()
Definition: portable_storage_from_bin.h:237
size_t m_count
Definition: portable_storage_from_bin.h:107
t_type read()
Definition: portable_storage_from_bin.h:176
#define SERIALIZE_TYPE_BOOL
Definition: portable_storage_base.h:62
static constexpr const size_t strict
Definition: portable_storage_from_bin.h:51
void set_limits(size_t objects, size_t fields, size_t strings)
Definition: portable_storage_from_bin.h:363
Definition: portable_storage_from_bin.h:50
unsigned int uint32_t
Definition: stdint.h:126
size_t & m_counter_ref
Definition: portable_storage_from_bin.h:92
#define SERIALIZE_TYPE_UINT16
Definition: portable_storage_base.h:58
signed short int16_t
Definition: stdint.h:122
boost::make_recursive_variant< array_entry_t< section >, array_entry_t< uint64_t >, array_entry_t< uint32_t >, array_entry_t< uint16_t >, array_entry_t< uint8_t >, array_entry_t< int64_t >, array_entry_t< int32_t >, array_entry_t< int16_t >, array_entry_t< int8_t >, array_entry_t< double >, array_entry_t< bool >, array_entry_t< std::string >, array_entry_t< section >, array_entry_t< boost::recursive_variant_ > >::type array_entry
Definition: portable_storage_base.h:159
throwable_buffer_reader(const void *ptr, size_t sz)
Definition: portable_storage_from_bin.h:118
Definition: portable_storage_from_bin.h:67
#define SERIALIZE_FLAG_ARRAY
Definition: portable_storage_base.h:66
unsigned __int64 uint64_t
Definition: stdint.h:136
size_t max_objects
Definition: portable_storage_from_bin.h:113
#define SERIALIZE_TYPE_ARRAY
Definition: portable_storage_base.h:64
#define false
Definition: stdbool.h:37
signed char int8_t
Definition: stdint.h:121
Definition: portable_storage_base.h:168
#define SERIALIZE_TYPE_INT8
Definition: portable_storage_base.h:55
void read_sec_name(std::string &sce_name)
Definition: portable_storage_from_bin.h:144
entry_container< t_entry_type >::type m_array
Definition: portable_storage_base.h:139
const char *const str
Definition: portlistingparse.c:23
#define SERIALIZE_TYPE_UINT8
Definition: portable_storage_base.h:59
TODO: (mj-xmr) This will be reduced in an another PR.
Definition: byte_slice.h:39
#define PORTABLE_RAW_SIZE_MARK_MASK
Definition: portable_storage_base.h:41
#define SERIALIZE_TYPE_DOUBLE
Definition: portable_storage_base.h:60
const T & move(const T &t)
Definition: gtest-port.h:1317
size_t max_fields
Definition: portable_storage_from_bin.h:114
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
void * memcpy(void *a, const void *b, size_t c)
Definition: glibc_compat.cpp:16
storage_entry read_se()
Definition: portable_storage_from_bin.h:257
signed __int64 int64_t
Definition: stdint.h:135
int bool
Definition: stdbool.h:35
#define PORTABLE_RAW_SIZE_MARK_DWORD
Definition: portable_storage_base.h:44
~recursuion_limitation_guard() noexcept(false)
Definition: portable_storage_from_bin.h:98
#define PORTABLE_RAW_SIZE_MARK_INT64
Definition: portable_storage_base.h:45
size_t m_fields
Definition: portable_storage_from_bin.h:110
signed int int32_t
Definition: stdint.h:123
size_t m_recursion_count
Definition: portable_storage_from_bin.h:108
#define RECURSION_LIMITATION()
Definition: portable_storage_from_bin.h:104
std::map< std::string, storage_entry > m_entries
Definition: portable_storage_base.h:170
#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL
Definition: portable_storage_from_bin.h:42
size_t m_strings
Definition: portable_storage_from_bin.h:111