bitsery
bitsery copied to clipboard
Problem with deserialization of structure - Assertion newOffset <= _endReadOffset
What's your question?
How to fix it?
Additional Context
Hello.
I have a problem with the deserialization of my structure. (Assertion newOffset <= _endReadOffset)
I have two strings (wrapped by Text4b) in the struct:
struct AuthFrameResponse
{
MessageType msg_type;
Text4b refresh_token;
Text4b access_token;
}
struct Text4b
{
uint32_t content_size{0};
std::string content;
static constexpr uint32_t MaxSize = std::numeric_limits<uint32_t>::max();
template <typename S>
void serialize(S &s)
{
if(content.size() > MaxSize)
{
throw std::runtime_error("content is too long");
}
s.value4b(content_size);
content.resize(content_size);
for(uint i=0; i<content_size; i++)
{
char c;
s.value1b(c);
content.push_back(c);
}
}
};
Code:
struct BitseryConfig
{
static constexpr bitsery::EndiannessType Endianness = bitsery::DefaultConfig::Endianness;
static constexpr bool CheckAdapterErrors = false;
static constexpr bool CheckDataErrors = false;
}; // struct BitseryConfig
template <class T>
bool fromBitseryBinary(std::vector<uint8_t> &bytes, T &t)
{
using InputAdapter = bitsery::InputBufferAdapter<std::vector<uint8_t>, BitseryConfig>;
auto state = bitsery::quickDeserialization<InputAdapter, T>(InputAdapter(std::begin(bytes), bytes.size()), t);
return state.first == bitsery::ReaderError::NoError;
}
namespace AuthProtocol
{
enum class MessageType : uint32_t
{
RES = 0,
AUTH_INIT,
AUTH_ERROR,
UPDATE_ACCESS_TOKEN_REQUEST,
UPDATE_ACCESS_TOKEN_RESPONSE,
CMD
};
struct Text4b
{
uint32_t content_size{0};
std::string content;
static constexpr uint32_t MaxSize = std::numeric_limits<uint32_t>::max();
template <typename S>
void serialize(S &s)
{
if(content.size() > MaxSize)
{
throw std::runtime_error("content is too long");
}
s.value4b(content_size);
content.resize(content_size);
for(uint i=0; i<content_size; i++)
{
char c;
s.value1b(c);
content.push_back(c);
}
}
};
struct AuthFrameResponse
{
MessageType t;
Text4b refresh_token;
Text4b access_token;
template <typename S>
void serialize(S &s)
{
s.value4b(t);
s.object(refresh_token);
s.object(access_token);
}
};
}// namespace
///... read via tcp
boost::asio::async_read(_socket, boost::asio::buffer(_recv_data), boost::asio::transfer_at_least(512), [&] (boost::system::error_code error, std::size_t bytes_transferred)
{
if (error)
{
std::cout << "RECV ERR message: " << error.message() << std::endl;
}
else if(bytes_transferred != 0)
{
std::cout << "receive_auth_response bytes_transferred: " << bytes_transferred << std::endl;
AuthProtocol::AuthFrameResponse response;
if (!fromBitseryBinary(_recv_data, response))
{
std::cout << "fromBitseryBinary error" << std::endl;
return;
}
}
});
Error:
receive_auth_response bytes_transferred: 722
/home/mhanusek/.conan/data/bitsery/5.1.0/_/_/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/include/bitsery/adapter/buffer.h:120: void bitsery::InputBufferAdapter<Buffer, Config>::readInternalValueChecked(bitsery::InputBufferAdapter<Buffer, Config>::TValue*, std::false_type) [with long unsigned int SIZE = 1; Buffer = std::vector<unsigned char>; Config = BitseryConfig; bitsery::InputBufferAdapter<Buffer, Config>::TValue = unsigned char; std::false_type = std::integral_constant<bool, false>]: Assertion `newOffset <= _endReadOffset' failed.
Hello,
There might be two things: First:
s.value4b(content_size);
content.resize(content_size);
for(uint i=0; i<content_size; i++)
{
char c;
s.value1b(c);
content.push_back(c);
}
is not correct. I think you wanted to write content[i] = c; instead of content.push(), but also I think that you might be able to delete content_size and simply use content.size() instead. That would become as simple as:
s.text1b(content);
Second, I'm not sure, but maybe the problem is with boost::asio::buffer(_recv_data). Maybe you expect to deserialize 1000bytes, but actually receive only 500?. TCP is streaming protocol, which means that it can split one message into multiple pieces.
I would suggest to:
- read "header" first, which would contain size of whole message (AuthFrameResponse).
- then read into separate buffer until you have all the bytes for the message.
- finally deserialize the message.
Hope that helps.