Commit 057b9aa2 authored by Dominik Charousset's avatar Dominik Charousset

Fix serialization of variant and sequences

Switch from platform-dependent `size_t` to `uint32_t` when serializing
the size of a sequence and from `size_t` to `uint8_t` when serializing
the type index of a `variant`. Fixed sizes for the integer types are
needed to ensure compatibility between 32-bit and 64-bit CAF nodes.

Relates #677.
parent a2f78b4d
...@@ -85,7 +85,16 @@ public: ...@@ -85,7 +85,16 @@ public:
} }
error begin_sequence(size_t& num_elements) override { error begin_sequence(size_t& num_elements) override {
return varbyte_decode(num_elements); // We serialize a `size_t` always in 32-bit, to guarantee compatibility
// with 32-bit nodes in the network.
// TODO: protect with `if constexpr (sizeof(size_t) > sizeof(uint32_t))`
// when switching to C++17 and pass `num_elements` directly to
// `varbyte_decode` in the `else` case
uint32_t x;
auto result = varbyte_decode(x);
if (!result)
num_elements = static_cast<size_t>(x);
return result;
} }
error end_sequence() override { error end_sequence() override {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <type_traits> #include <type_traits>
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/config.hpp"
#include "caf/streambuf.hpp" #include "caf/streambuf.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
...@@ -83,7 +84,12 @@ public: ...@@ -83,7 +84,12 @@ public:
} }
error begin_sequence(size_t& list_size) override { error begin_sequence(size_t& list_size) override {
return varbyte_encode(list_size); // TODO: protect with `if constexpr (sizeof(size_t) > sizeof(uint32_t))`
// when switching to C++17
CAF_ASSERT(list_size <= std::numeric_limits<uint32_t>::max());
// Serialize a `size_t` always in 32-bit, to guarantee compatibility with
// 32-bit nodes in the network.
return varbyte_encode(static_cast<uint32_t>(list_size));
} }
error end_sequence() override { error end_sequence() override {
......
...@@ -451,7 +451,7 @@ bool operator==(const variant<Ts...>& x, const T& y) { ...@@ -451,7 +451,7 @@ bool operator==(const variant<Ts...>& x, const T& y) {
/// @relates variant /// @relates variant
template <class T> template <class T>
struct variant_reader { struct variant_reader {
size_t& type_tag; uint8_t& type_tag;
T& x; T& x;
}; };
...@@ -467,7 +467,8 @@ template <class Inspector, class... Ts> ...@@ -467,7 +467,8 @@ template <class Inspector, class... Ts>
typename std::enable_if<Inspector::reads_state, typename std::enable_if<Inspector::reads_state,
typename Inspector::result_type>::type typename Inspector::result_type>::type
inspect(Inspector& f, variant<Ts...>& x) { inspect(Inspector& f, variant<Ts...>& x) {
auto type_tag = x.index(); // We use a single byte for the type index on the wire.
auto type_tag = static_cast<uint8_t>(x.index());
variant_reader<variant<Ts...>> helper{type_tag, x}; variant_reader<variant<Ts...>> helper{type_tag, x};
return f(meta::omittable(), type_tag, helper); return f(meta::omittable(), type_tag, helper);
} }
...@@ -475,7 +476,7 @@ inspect(Inspector& f, variant<Ts...>& x) { ...@@ -475,7 +476,7 @@ inspect(Inspector& f, variant<Ts...>& x) {
/// @relates variant /// @relates variant
template <class T> template <class T>
struct variant_writer { struct variant_writer {
size_t& type_tag; uint8_t& type_tag;
T& x; T& x;
}; };
...@@ -513,7 +514,8 @@ template <class Inspector, class... Ts> ...@@ -513,7 +514,8 @@ template <class Inspector, class... Ts>
typename std::enable_if<Inspector::writes_state, typename std::enable_if<Inspector::writes_state,
typename Inspector::result_type>::type typename Inspector::result_type>::type
inspect(Inspector& f, variant<Ts...>& x) { inspect(Inspector& f, variant<Ts...>& x) {
size_t type_tag; // We use a single byte for the type index on the wire.
uint8_t type_tag;
variant_writer<variant<Ts...>> helper{type_tag, x}; variant_writer<variant<Ts...>> helper{type_tag, x};
return f(meta::omittable(), type_tag, helper); return f(meta::omittable(), type_tag, helper);
} }
......
...@@ -465,7 +465,7 @@ CAF_TEST(byte_sequence_optimization) { ...@@ -465,7 +465,7 @@ CAF_TEST(byte_sequence_optimization) {
CAF_TEST(long_sequences) { CAF_TEST(long_sequences) {
std::vector<char> data; std::vector<char> data;
binary_serializer sink{nullptr, data}; binary_serializer sink{nullptr, data};
size_t n = 12345678900u; size_t n = std::numeric_limits<uint32_t>::max();
sink.begin_sequence(n); sink.begin_sequence(n);
sink.end_sequence(); sink.end_sequence();
binary_deserializer source{nullptr, data}; binary_deserializer source{nullptr, data};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment