From 1bbe619689c8f3089f484be77bf80dfb6afca360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20=C3=81vila=20de=20Esp=C3=ADndola?= Date: Sun, 12 Jan 2020 20:11:05 -0800 Subject: [PATCH] types: Fix encoding of negative varint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would sometimes produce an unnecessary extra 0xff prefix byte. The new encoding matches what cassandra does. This was both a efficiency and correctness issue, as using varint in a key could produce different tokens. Fixes #5656 Signed-off-by: Rafael Ávila de Espíndola (cherry picked from commit c89c90d07f2b30697cfb82809abbdc863c076523) --- test/boost/types_test.cc | 2 ++ types.cc | 15 +++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/test/boost/types_test.cc b/test/boost/types_test.cc index 5af0c3704c..350d8c8a58 100644 --- a/test/boost/types_test.cc +++ b/test/boost/types_test.cc @@ -415,6 +415,8 @@ BOOST_AUTO_TEST_CASE(test_varint) { BOOST_CHECK_EQUAL(value_cast(varint_type->deserialize(from_hex("00deadbeef"))), boost::multiprecision::cpp_int("0xdeadbeef")); BOOST_CHECK_EQUAL(value_cast(varint_type->deserialize(from_hex("00ffffffffffffffffffffffffffffffff"))), boost::multiprecision::cpp_int("340282366920938463463374607431768211455")); + BOOST_REQUIRE_EQUAL(from_hex("80000000"), varint_type->decompose(boost::multiprecision::cpp_int(-2147483648))); + test_parsing_fails(varint_type, "1A"); } diff --git a/types.cc b/types.cc index ee0cc3cb35..8dd80dd7f1 100644 --- a/types.cc +++ b/types.cc @@ -2082,12 +2082,19 @@ static size_t concrete_serialized_size(const string_type_impl::native_type& v) { static size_t concrete_serialized_size(const bytes_type_impl::native_type& v) { return v.size(); } static size_t concrete_serialized_size(const inet_addr_type_impl::native_type& v) { return v.get().size(); } -static size_t concrete_serialized_size(const boost::multiprecision::cpp_int& num) { - if (!num) { +static size_t concrete_serialized_size_aux(const boost::multiprecision::cpp_int& num) { + if (num) { + return align_up(boost::multiprecision::msb(num) + 2, 8u) / 8; + } else { return 1; } - auto pnum = abs(num); - return align_up(boost::multiprecision::msb(pnum) + 2, 8u) / 8; +} + +static size_t concrete_serialized_size(const boost::multiprecision::cpp_int& num) { + if (num < 0) { + return concrete_serialized_size_aux(-num - 1); + } + return concrete_serialized_size_aux(num); } static size_t concrete_serialized_size(const varint_type_impl::native_type& v) {