diff --git a/include/mysql/impl/binary_deserialization.ipp b/include/mysql/impl/binary_deserialization.ipp index cfe8e3f2..6236b463 100644 --- a/include/mysql/impl/binary_deserialization.ipp +++ b/include/mysql/impl/binary_deserialization.ipp @@ -130,6 +130,7 @@ inline mysql::error_code mysql::detail::deserialize_binary_row( // Null bitmap null_bitmap_traits null_bitmap (binary_row_null_bitmap_offset, num_fields); const std::uint8_t* null_bitmap_begin = ctx.first(); + if (!ctx.enough_size(null_bitmap.byte_count())) return make_error_code(Error::incomplete_message); ctx.advance(null_bitmap.byte_count()); // Actual values diff --git a/test/common/test_common.hpp b/test/common/test_common.hpp index d5a5106a..d16e1507 100644 --- a/test/common/test_common.hpp +++ b/test/common/test_common.hpp @@ -4,9 +4,12 @@ #include "mysql/value.hpp" #include "mysql/row.hpp" #include +#include #include #include #include +#include +#include namespace mysql { @@ -115,6 +118,15 @@ inline void compare_buffers(std::string_view s0, std::string_view s1, const char EXPECT_EQ(s0, s1) << msg << ":\n" << buffer_diff(s0, s1); } +struct named_test {}; + +template >> +std::ostream& operator<<(std::ostream& os, const T& v) { return os << v.name; } + +constexpr auto test_name_generator = [](const auto& param_info) { + return param_info.param.name; +}; + } } diff --git a/test/unit/binary_deserialization.cpp b/test/unit/binary_deserialization.cpp index db3e083a..b8610bcc 100644 --- a/test/unit/binary_deserialization.cpp +++ b/test/unit/binary_deserialization.cpp @@ -23,6 +23,20 @@ namespace using mysql::operator<<; +std::vector make_meta( + const std::vector& types +) +{ + std::vector res; + for (const auto type: types) + { + column_definition_packet coldef; + coldef.type = type; + res.emplace_back(coldef); + } + return res; +} + // for deserialize_binary_value struct BinaryValueParam { @@ -158,16 +172,7 @@ struct DeserializeBinaryRowTest : public TestWithParam TEST_P(DeserializeBinaryRowTest, CorrectFormat_SetsOutputValueReturnsTrue) { - // Meta - std::vector meta; - for (const auto type: GetParam().types) - { - column_definition_packet coldef; - coldef.type = type; - meta.emplace_back(coldef); - } - - // Context + auto meta = make_meta(GetParam().types); const auto& buffer = GetParam().from; DeserializationContext ctx (buffer.data(), buffer.data() + buffer.size(), capabilities()); @@ -217,6 +222,55 @@ INSTANTIATE_TEST_SUITE_P(Default, DeserializeBinaryRowTest, testing::Values( ) )); +// Error cases for deserialize_binary_row +struct BinaryRowErrorParam : named_test +{ + std::string name; + std::vector from; + Error expected; + std::vector types; + + BinaryRowErrorParam( + std::string name, + std::vector from, + Error expected, + std::vector types + ): + name(std::move(name)), + from(std::move(from)), + expected(expected), + types(std::move(types)) + { + } +}; + +struct DeserializeBinaryRowErrorTest : public TestWithParam +{ +}; + +TEST_P(DeserializeBinaryRowErrorTest, ErrorCondition_ReturnsErrorCode) +{ + auto meta = make_meta(GetParam().types); + const auto& buffer = GetParam().from; + DeserializationContext ctx (buffer.data(), buffer.data() + buffer.size(), capabilities()); + + std::vector actual; + auto err = deserialize_binary_row(ctx, meta, actual); + EXPECT_EQ(err, make_error_code(GetParam().expected)); +} + +INSTANTIATE_TEST_SUITE_P(Default, DeserializeBinaryRowErrorTest, testing::Values( + BinaryRowErrorParam("no_space_null_bitmap_1", {}, Error::incomplete_message, {protocol_field_type::tiny}), + BinaryRowErrorParam("no_space_null_bitmap_2", {0xfc}, Error::incomplete_message, + std::vector(7, protocol_field_type::tiny)), + BinaryRowErrorParam("no_space_value_single", {0x00}, Error::incomplete_message, {protocol_field_type::tiny}), + BinaryRowErrorParam("no_space_value_last", {0x00, 0x01}, Error::incomplete_message, + std::vector(2, protocol_field_type::tiny)), + BinaryRowErrorParam("no_space_value_middle", {0x00, 0x01}, Error::incomplete_message, + std::vector(3, protocol_field_type::tiny)), + BinaryRowErrorParam("extra_bytes", {0x00, 0x01, 0x02}, Error::extra_bytes, {protocol_field_type::tiny}) +), test_name_generator); + } // anon namespace