diff options
Diffstat (limited to '')
-rw-r--r-- | src/serialization/crypto.h | 2 | ||||
-rw-r--r-- | src/serialization/serialization.h | 26 | ||||
-rw-r--r-- | src/serialization/tuple.h | 162 |
3 files changed, 82 insertions, 108 deletions
diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 896d00583..2da26abe7 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -81,7 +81,7 @@ BLOB_SERIALIZER(crypto::chacha_iv); BLOB_SERIALIZER(crypto::hash); BLOB_SERIALIZER(crypto::hash8); BLOB_SERIALIZER(crypto::public_key); -BLOB_SERIALIZER(crypto::secret_key); +BLOB_SERIALIZER_FORCED(crypto::secret_key); BLOB_SERIALIZER(crypto::key_derivation); BLOB_SERIALIZER(crypto::key_image); BLOB_SERIALIZER(crypto::signature); diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index d1f97e324..33edf3f62 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -50,13 +50,16 @@ #include <boost/type_traits/integral_constant.hpp> #include <boost/mpl/bool.hpp> -/*! \struct is_blob_type +/*! \struct is_blob_type / is_blob_forced * - * \brief a descriptor for dispatching serialize + * \brief descriptors for dispatching serialize: whether to take byte-wise copy/store to type */ template <class T> struct is_blob_type { typedef boost::false_type type; }; +template <class T> +struct is_blob_forced: std::false_type {}; + /*! \fn do_serialize(Archive &ar, T &v) * * \brief main function for dispatching serialization for a given pair of archive and value types @@ -68,6 +71,8 @@ struct is_blob_type { typedef boost::false_type type; }; template <class Archive, class T> inline std::enable_if_t<is_blob_type<T>::type::value, bool> do_serialize(Archive &ar, T &v) { + static_assert(std::is_trivially_copyable<T>() || is_blob_forced<T>(), + "sanity check: types that can't be trivially copied shouldn't be using the blob serializer"); ar.serialize_blob(&v, sizeof(v)); return true; } @@ -94,6 +99,9 @@ inline bool do_serialize(Archive &ar, bool &v) /*! \macro BLOB_SERIALIZER * * \brief makes the type have a blob serializer trait defined + * + * In case your type is not a good candidate to be blob serialized, a static assertion may be thrown + * at compile-time. */ #define BLOB_SERIALIZER(T) \ template<> \ @@ -101,6 +109,20 @@ inline bool do_serialize(Archive &ar, bool &v) typedef boost::true_type type; \ } +/*! \macro BLOB_SERIALIZER_FORCED + * + * \brief makes the type have a blob serializer trait defined, even if it isn't trivially copyable + * + * Caution: do NOT use this macro for your type <T>, unless you are absolutely sure that moving raw + * bytes in/out of this type will not cause undefined behavior. Any types with managed memory + * (e.g. vector, string, etc) will segfault and/or cause memory errors if you use this macro with + * that type. + */ +#define BLOB_SERIALIZER_FORCED(T) \ + BLOB_SERIALIZER(T); \ + template<> \ + struct is_blob_forced<T>: std::true_type {}; + /*! \macro VARIANT_TAG * * \brief Adds the tag \tag to the \a Archive of \a Type diff --git a/src/serialization/tuple.h b/src/serialization/tuple.h index d9592bc96..b1ef94097 100644 --- a/src/serialization/tuple.h +++ b/src/serialization/tuple.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023, The Monero Project +// Copyright (c) 2014-2024, The Monero Project // // All rights reserved. // @@ -29,7 +29,7 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once -#include <memory> +#include <tuple> #include "serialization.h" namespace serialization @@ -51,119 +51,71 @@ namespace serialization } } -template <template <bool> class Archive, class E0, class E1, class E2> -inline bool do_serialize(Archive<false>& ar, std::tuple<E0,E1,E2>& p) +template <size_t I, bool BackwardsCompat, bool W, template <bool> class Archive, typename... Ts> +bool do_serialize_tuple_nth(Archive<W>& ar, std::tuple<Ts...>& v) { - size_t cnt; - ar.begin_array(cnt); - if (!ar.good()) - return false; - if (cnt != 3) - return false; + static constexpr const size_t tuple_size = std::tuple_size<std::tuple<Ts...>>(); + static_assert(I <= tuple_size, "bad call"); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; + if constexpr (I == 0) + { + // If BackwardsCompat is true, we serialize the size of 3-tuples and 4-tuples + if constexpr (BackwardsCompat && (tuple_size == 3 || tuple_size == 4)) + { + size_t cnt = tuple_size; + ar.begin_array(cnt); + if (cnt != tuple_size) + return false; + } + else + { + ar.begin_array(); + } + } + else if constexpr (I < tuple_size) + { + ar.delimit_array(); + } - ar.end_array(); - return true; + if constexpr (I == tuple_size) + { + ar.end_array(); + return ar.good(); + } + else + { + if (!::serialization::detail::serialize_tuple_element(ar, std::get<I>(v)) + || !ar.good()) + return false; + + return do_serialize_tuple_nth<I + 1, BackwardsCompat>(ar, v); + } } -template <template <bool> class Archive, class E0, class E1, class E2> -inline bool do_serialize(Archive<true>& ar, std::tuple<E0,E1,E2>& p) +template <bool BackwardsCompat, bool W, template <bool> class Archive, typename... Ts> +bool do_serialize_tuple(Archive<W>& ar, std::tuple<Ts...>& v) { - ar.begin_array(3); - if (!ar.good()) - return false; - if(!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; - ar.end_array(); - return true; + return do_serialize_tuple_nth<0, BackwardsCompat>(ar, v); } -template <template <bool> class Archive, class E0, class E1, class E2, class E3> -inline bool do_serialize(Archive<false>& ar, std::tuple<E0,E1,E2,E3>& p) +template <bool W, template <bool> class Archive, typename... Ts> +bool do_serialize(Archive<W>& ar, std::tuple<Ts...>& v) { - size_t cnt; - ar.begin_array(cnt); - if (!ar.good()) - return false; - if (cnt != 4) - return false; + return do_serialize_tuple<true>(ar, v); +} - if (!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<3>(p))) - return false; - if (!ar.good()) - return false; +#define TUPLE_COMPACT_FIELDS(v) \ + do { \ + if (!do_serialize_tuple<false>(ar, v) || !ar.good()) \ + return false; \ + } while (0); - ar.end_array(); - return true; -} +#define TUPLE_COMPACT_FIELD_N(t, v) \ + do { \ + ar.tag(t); \ + TUPLE_COMPACT_FIELDS(v); \ + } while (0); -template <template <bool> class Archive, class E0, class E1, class E2, class E3> -inline bool do_serialize(Archive<true>& ar, std::tuple<E0,E1,E2,E3>& p) -{ - ar.begin_array(4); - if (!ar.good()) - return false; - if(!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<3>(p))) - return false; - if (!ar.good()) - return false; - ar.end_array(); - return true; -} +#define TUPLE_COMPACT_FIELD(f) TUPLE_COMPACT_FIELD_N(#f, f) +#define TUPLE_COMPACT_FIELD_F(f) TUPLE_COMPACT_FIELD_N(#f, v.f) |