serialization: fix infinite loops and clean up dispatching
Resolves #8687
This commit is contained in:
parent
8eab181fe1
commit
33e3f72d24
|
@ -52,7 +52,7 @@ namespace cryptonote
|
|||
|
||||
// load
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false>& ar)
|
||||
bool member_do_serialize(Archive<false>& ar)
|
||||
{
|
||||
// size - 1 - because of variant tag
|
||||
for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
|
||||
|
@ -73,7 +73,7 @@ namespace cryptonote
|
|||
|
||||
// store
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true>& ar)
|
||||
bool member_do_serialize(Archive<true>& ar)
|
||||
{
|
||||
if(TX_EXTRA_PADDING_MAX_COUNT < size)
|
||||
return false;
|
||||
|
@ -129,7 +129,7 @@ namespace cryptonote
|
|||
|
||||
// load
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<false>& ar)
|
||||
bool member_do_serialize(Archive<false>& ar)
|
||||
{
|
||||
std::string field;
|
||||
if(!::do_serialize(ar, field))
|
||||
|
@ -142,7 +142,7 @@ namespace cryptonote
|
|||
|
||||
// store
|
||||
template <template <bool> class Archive>
|
||||
bool do_serialize(Archive<true>& ar)
|
||||
bool member_do_serialize(Archive<true>& ar)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
binary_archive<true> oar(oss);
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace serialization
|
|||
typename std::enable_if<!use_container_varint<T>(), bool>::type
|
||||
serialize_container_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
return do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template<typename Archive, typename T>
|
||||
|
@ -52,7 +52,7 @@ namespace serialization
|
|||
static constexpr const bool previously_varint = std::is_same<uint64_t, T>() || std::is_same<uint32_t, T>();
|
||||
|
||||
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
|
||||
return ::do_serialize(ar, e);
|
||||
return do_serialize(ar, e);
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -42,14 +42,12 @@ struct debug_archive : public json_archive<W> {
|
|||
};
|
||||
|
||||
template <class T>
|
||||
struct serializer<debug_archive<true>, T>
|
||||
static inline bool do_serialize(debug_archive<true> &ar, T &v)
|
||||
{
|
||||
static void serialize(debug_archive<true> &ar, T &v)
|
||||
{
|
||||
ar.begin_object();
|
||||
ar.tag(variant_serialization_traits<debug_archive<true>, T>::get_tag());
|
||||
serializer<json_archive<true>, T>::serialize(ar, v);
|
||||
do_serialize(static_cast<json_archive<true>&>(ar), v);
|
||||
ar.end_object();
|
||||
ar.stream() << std::endl;
|
||||
}
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
#include "cryptonote_basic/difficulty.h"
|
||||
#include "serialization.h"
|
||||
|
||||
template<> struct is_basic_type<cryptonote::difficulty_type> { typedef boost::true_type type; };
|
||||
|
||||
template <template <bool> class Archive>
|
||||
inline bool do_serialize(Archive<false>& ar, cryptonote::difficulty_type &diff)
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace serialization
|
|||
typename std::enable_if<!use_pair_varint<T>(), bool>::type
|
||||
serialize_pair_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
return do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template<typename Archive, typename T>
|
||||
|
@ -57,7 +57,7 @@ namespace serialization
|
|||
static constexpr const bool previously_varint = std::is_same<uint64_t, T>();
|
||||
|
||||
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
|
||||
return ::do_serialize(ar, e);
|
||||
return do_serialize(ar, e);
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -57,73 +57,30 @@
|
|||
template <class T>
|
||||
struct is_blob_type { typedef boost::false_type type; };
|
||||
|
||||
/*! \struct has_free_serializer
|
||||
*
|
||||
* \brief a descriptor for dispatching serialize
|
||||
*/
|
||||
template <class T>
|
||||
struct has_free_serializer { typedef boost::true_type type; };
|
||||
|
||||
/*! \struct is_basic_type
|
||||
*
|
||||
* \brief a descriptor for dispatching serialize
|
||||
*/
|
||||
template <class T>
|
||||
struct is_basic_type { typedef boost::false_type type; };
|
||||
|
||||
template<typename F, typename S>
|
||||
struct is_basic_type<std::pair<F,S>> { typedef boost::true_type type; };
|
||||
template<>
|
||||
struct is_basic_type<std::string> { typedef boost::true_type type; };
|
||||
|
||||
/*! \struct serializer
|
||||
*
|
||||
* \brief ... wouldn't a class be better?
|
||||
*
|
||||
* \detailed The logic behind serializing data. Places the archive
|
||||
* data into the supplied parameter. This dispatches based on the
|
||||
* supplied \a T template parameter's traits of is_blob_type or it is
|
||||
* an integral (as defined by the is_integral trait). Depends on the
|
||||
* \a Archive parameter to have overloaded the serialize_blob(T v,
|
||||
* size_t size) and serialize_int(T v) base on which trait it
|
||||
* applied. When the class has neither types, it falls to the
|
||||
* overloaded method do_serialize(Archive ar) in T to do the work.
|
||||
*/
|
||||
template <class Archive, class T>
|
||||
struct serializer{
|
||||
static bool serialize(Archive &ar, T &v) {
|
||||
return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type(), typename is_basic_type<T>::type());
|
||||
}
|
||||
template<typename A>
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::true_type, A a) {
|
||||
ar.serialize_blob(&v, sizeof(v));
|
||||
return true;
|
||||
}
|
||||
template<typename A>
|
||||
static bool serialize(Archive &ar, T &v, boost::true_type, boost::false_type, A a) {
|
||||
ar.serialize_int(v);
|
||||
return true;
|
||||
}
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::false_type) {
|
||||
//serialize_custom(ar, v, typename has_free_serializer<T>::type());
|
||||
return v.do_serialize(ar);
|
||||
}
|
||||
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::true_type) {
|
||||
//serialize_custom(ar, v, typename has_free_serializer<T>::type());
|
||||
return do_serialize(ar, v);
|
||||
}
|
||||
static void serialize_custom(Archive &ar, T &v, boost::true_type) {
|
||||
}
|
||||
};
|
||||
|
||||
/*! \fn do_serialize(Archive &ar, T &v)
|
||||
*
|
||||
* \brief just calls the serialize function defined for ar and v...
|
||||
* \brief main function for dispatching serialization for a given pair of archive and value types
|
||||
*
|
||||
* Types marked true with is_blob_type<T> will be serialized as a blob, integral types will be
|
||||
* serialized as integers, and types who have a `member_do_serialize` method will be serialized
|
||||
* using that method. Booleans are serialized like blobs.
|
||||
*/
|
||||
template <class Archive, class T>
|
||||
inline bool do_serialize(Archive &ar, T &v)
|
||||
inline std::enable_if_t<is_blob_type<T>::type::value, bool> do_serialize(Archive &ar, T &v)
|
||||
{
|
||||
return ::serializer<Archive, T>::serialize(ar, v);
|
||||
ar.serialize_blob(&v, sizeof(v));
|
||||
return true;
|
||||
}
|
||||
template <class Archive, class T>
|
||||
inline std::enable_if_t<boost::is_integral<T>::value, bool> do_serialize(Archive &ar, T &v)
|
||||
{
|
||||
ar.serialize_int(v);
|
||||
return true;
|
||||
}
|
||||
template <class Archive, class T>
|
||||
inline auto do_serialize(Archive &ar, T &v) -> decltype(v.member_do_serialize(ar), true)
|
||||
{
|
||||
return v.member_do_serialize(ar);
|
||||
}
|
||||
template <class Archive>
|
||||
inline bool do_serialize(Archive &ar, bool &v)
|
||||
|
@ -144,16 +101,6 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
typedef boost::true_type type; \
|
||||
}
|
||||
|
||||
/*! \macro FREE_SERIALIZER
|
||||
*
|
||||
* \brief adds the has_free_serializer to the type
|
||||
*/
|
||||
#define FREE_SERIALIZER(T) \
|
||||
template<> \
|
||||
struct has_free_serializer<T> { \
|
||||
typedef boost::true_type type; \
|
||||
}
|
||||
|
||||
/*! \macro VARIANT_TAG
|
||||
*
|
||||
* \brief Adds the tag \tag to the \a Archive of \a Type
|
||||
|
@ -174,7 +121,7 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
*/
|
||||
#define BEGIN_SERIALIZE() \
|
||||
template <bool W, template <bool> class Archive> \
|
||||
bool do_serialize(Archive<W> &ar) {
|
||||
bool member_do_serialize(Archive<W> &ar) {
|
||||
|
||||
/*! \macro BEGIN_SERIALIZE_OBJECT
|
||||
*
|
||||
|
@ -183,7 +130,7 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
*/
|
||||
#define BEGIN_SERIALIZE_OBJECT() \
|
||||
template <bool W, template <bool> class Archive> \
|
||||
bool do_serialize(Archive<W> &ar) { \
|
||||
bool member_do_serialize(Archive<W> &ar) { \
|
||||
ar.begin_object(); \
|
||||
bool r = do_serialize_object(ar); \
|
||||
ar.end_object(); \
|
||||
|
@ -197,11 +144,6 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \
|
||||
::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving())
|
||||
|
||||
/*! \macro PREPARE_CUSTOM_DEQUE_SERIALIZATION
|
||||
*/
|
||||
#define PREPARE_CUSTOM_DEQUE_SERIALIZATION(size, vec) \
|
||||
::serialization::detail::prepare_custom_deque_serialization(size, vec, typename Archive<W>::is_saving())
|
||||
|
||||
/*! \macro END_SERIALIZE
|
||||
* \brief self-explanatory
|
||||
*/
|
||||
|
@ -209,16 +151,6 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
return ar.good(); \
|
||||
}
|
||||
|
||||
/*! \macro VALUE(f)
|
||||
* \brief the same as FIELD(f)
|
||||
*/
|
||||
#define VALUE(f) \
|
||||
do { \
|
||||
ar.tag(#f); \
|
||||
bool r = ::do_serialize(ar, f); \
|
||||
if (!r || !ar.good()) return false; \
|
||||
} while(0);
|
||||
|
||||
/*! \macro FIELD_N(t,f)
|
||||
*
|
||||
* \brief serializes a field \a f tagged \a t
|
||||
|
@ -226,7 +158,7 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
#define FIELD_N(t, f) \
|
||||
do { \
|
||||
ar.tag(t); \
|
||||
bool r = ::do_serialize(ar, f); \
|
||||
bool r = do_serialize(ar, f); \
|
||||
if (!r || !ar.good()) return false; \
|
||||
} while(0);
|
||||
|
||||
|
@ -237,7 +169,7 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
#define FIELD(f) \
|
||||
do { \
|
||||
ar.tag(#f); \
|
||||
bool r = ::do_serialize(ar, f); \
|
||||
bool r = do_serialize(ar, f); \
|
||||
if (!r || !ar.good()) return false; \
|
||||
} while(0);
|
||||
|
||||
|
@ -247,7 +179,7 @@ inline bool do_serialize(Archive &ar, bool &v)
|
|||
*/
|
||||
#define FIELDS(f) \
|
||||
do { \
|
||||
bool r = ::do_serialize(ar, f); \
|
||||
bool r = do_serialize(ar, f); \
|
||||
if (!r || !ar.good()) return false; \
|
||||
} while(0);
|
||||
|
||||
|
@ -317,17 +249,6 @@ namespace serialization {
|
|||
vec.resize(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/)
|
||||
{
|
||||
vec.resize(size);
|
||||
}
|
||||
|
||||
/*! \fn do_check_stream_state
|
||||
*
|
||||
* \brief self explanatory
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace serialization
|
|||
template <typename Archive, class T>
|
||||
bool serialize_tuple_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
return do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template <typename Archive>
|
||||
|
|
|
@ -72,7 +72,7 @@ struct variant_reader
|
|||
{
|
||||
if(variant_serialization_traits<Archive, current_type>::get_tag() == t) {
|
||||
current_type x;
|
||||
if(!::do_serialize(ar, x))
|
||||
if(!do_serialize(ar, x))
|
||||
{
|
||||
ar.set_fail();
|
||||
return false;
|
||||
|
@ -100,19 +100,13 @@ struct variant_reader<Archive, Variant, TBegin, TBegin>
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template <template <bool> class Archive, BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
struct serializer<Archive<false>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
|
||||
{
|
||||
typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
|
||||
typedef typename Archive<false>::variant_tag_type variant_tag_type;
|
||||
typedef typename variant_type::types types;
|
||||
|
||||
static bool serialize(Archive<false> &ar, variant_type &v) {
|
||||
variant_tag_type t;
|
||||
template <template <bool> class Archive, typename... T>
|
||||
static bool do_serialize(Archive<false> &ar, boost::variant<T...> &v) {
|
||||
using types = typename boost::variant<T...>::types;
|
||||
typename Archive<false>::variant_tag_type t;
|
||||
ar.begin_variant();
|
||||
ar.read_variant_tag(t);
|
||||
if(!variant_reader<Archive<false>, variant_type,
|
||||
if(!variant_reader<Archive<false>, boost::variant<T...>,
|
||||
typename boost::mpl::begin<types>::type,
|
||||
typename boost::mpl::end<types>::type>::read(ar, v, t))
|
||||
{
|
||||
|
@ -121,27 +115,21 @@ struct serializer<Archive<false>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
|
|||
}
|
||||
ar.end_variant();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <template <bool> class Archive, BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
||||
struct serializer<Archive<true>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
|
||||
template <template <bool> class Archive>
|
||||
struct variant_write_visitor : public boost::static_visitor<bool>
|
||||
{
|
||||
typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
|
||||
//typedef typename Archive<true>::variant_tag_type variant_tag_type;
|
||||
|
||||
struct visitor : public boost::static_visitor<bool>
|
||||
{
|
||||
Archive<true> &ar;
|
||||
|
||||
visitor(Archive<true> &a) : ar(a) { }
|
||||
variant_write_visitor(Archive<true> &a) : ar(a) { }
|
||||
|
||||
template <class T>
|
||||
bool operator ()(T &rv) const
|
||||
{
|
||||
ar.begin_variant();
|
||||
ar.write_variant_tag(variant_serialization_traits<Archive<true>, T>::get_tag());
|
||||
if(!::do_serialize(ar, rv))
|
||||
if(!do_serialize(ar, rv))
|
||||
{
|
||||
ar.set_fail();
|
||||
return false;
|
||||
|
@ -149,9 +137,10 @@ struct serializer<Archive<true>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
|
|||
ar.end_variant();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
static bool serialize(Archive<true> &ar, variant_type &v) {
|
||||
return boost::apply_visitor(visitor(ar), v);
|
||||
}
|
||||
};
|
||||
|
||||
template <template <bool> class Archive, typename... T>
|
||||
static bool do_serialize(Archive<true> &ar, boost::variant<T...> &v)
|
||||
{
|
||||
return boost::apply_visitor(variant_write_visitor<Archive>(ar), v);
|
||||
}
|
||||
|
|
|
@ -59,9 +59,7 @@ struct Struct
|
|||
};
|
||||
|
||||
template <class Archive>
|
||||
struct serializer<Archive, Struct>
|
||||
{
|
||||
static bool serialize(Archive &ar, Struct &s) {
|
||||
static bool do_serialize(Archive &ar, Struct &s) {
|
||||
ar.begin_object();
|
||||
ar.tag("a");
|
||||
ar.serialize_int(s.a);
|
||||
|
@ -71,8 +69,7 @@ struct serializer<Archive, Struct>
|
|||
ar.serialize_blob(s.blob, sizeof(s.blob));
|
||||
ar.end_object();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct Struct1
|
||||
{
|
||||
|
@ -122,6 +119,23 @@ bool try_parse(const string &blob)
|
|||
return serialization::parse_binary(blob, s1);
|
||||
}
|
||||
|
||||
namespace example_namespace
|
||||
{
|
||||
struct ADLExampleStruct
|
||||
{
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
template <class Archive>
|
||||
static bool do_serialize(Archive &ar, ADLExampleStruct &aes)
|
||||
{
|
||||
ar.begin_object();
|
||||
FIELD_N("custom_fieldname", aes.msg);
|
||||
ar.end_object();
|
||||
return ar.good();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Serialization, BinaryArchiveInts) {
|
||||
uint64_t x = 0xff00000000, x1;
|
||||
|
||||
|
@ -1178,3 +1192,18 @@ TEST(Serialization, difficulty_type)
|
|||
|
||||
ASSERT_EQ(v_original, v_unserialized);
|
||||
}
|
||||
|
||||
TEST(Serialization, adl_free_function)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss);
|
||||
|
||||
const std::string msg = "Howdy, World!";
|
||||
example_namespace::ADLExampleStruct aes{msg};
|
||||
|
||||
ASSERT_TRUE(serialization::serialize(ar, aes));
|
||||
|
||||
// VVVVVVVVVVVVVVVVVVVVVVVVVV weird string serialization artifact
|
||||
const std::string expected = "{\"custom_fieldname\": " + std::to_string(msg.size()) + '"' + epee::string_tools::buff_to_hex_nodelimer(msg) + "\"}";
|
||||
EXPECT_EQ(expected, ss.str());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue