From 1ab2bb69b8a6a05d9a29d3464aad03d4eabed963 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Fri, 30 Jun 2023 12:58:57 +0800 Subject: [PATCH] keys: do not use zip_iterator for printing key components boost's the operator==() implementation of boost's zip_iterator returns true only if all elements in enclosed tuple of zip_iterator are equal. and the zip_iterator always advances all the iterators in the enclosed tuple. but in our case, some components might be missing. in other words, the size of the `components` might be smaller than that of the `types` range. so, when the zip_iterator advances past the end of the components, scylla starts reading out of bounds. because zip_iterator does not allow us to customize how it implements the equal operator. and we cannot deduce the size of components without reading all of them. so in this change, we partially revert 3738fcbe054ef1540f262079d89e44c9b873769e, instead of using fmt::join(), just iterate through the components manually. this should avoid the out-of-bound reading, and also preserve the original behavior. Branches: 5.3 Fixes #14435 Signed-off-by: Kefu Chai Closes #14457 --- keys.hh | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/keys.hh b/keys.hh index 7fbb761625..9bbbd20cff 100644 --- a/keys.hh +++ b/keys.hh @@ -16,9 +16,6 @@ #include "utils/utf8.hh" #include "replica/database_fwd.hh" #include "schema/schema_fwd.hh" -#include -#include -#include #include #include @@ -773,26 +770,23 @@ namespace detail { template auto format_pk(const WithSchemaWrapper& pk, FormatContext& ctx) { const auto& [schema, key] = pk; - const auto& types = key.get_compound_type(schema)->types(); - const auto components = key.components(schema); - return fmt::format_to( - ctx.out(), "{}", - fmt::join(boost::make_iterator_range( - boost::make_zip_iterator(boost::make_tuple(types.begin(), - components.begin())), - boost::make_zip_iterator(boost::make_tuple(types.end(), - components.end()))) | - boost::adaptors::transformed([](const auto& type_and_component) { - auto& [type, component] = type_and_component; - auto key = type->to_string(to_bytes(component)); - if (!utils::utf8::validate((const uint8_t *) key.data(), key.size())) { - return sstring(""); - } - return key; - }), - ":")); - + auto type_iterator = key.get_compound_type(schema)->types().begin(); + bool first = true; + auto out = ctx.out(); + for (auto&& component : key.components(schema)) { + if (!first) { + out = fmt::format_to(out, "{}", ":"); + } + first = false; + auto key = (*type_iterator++)->to_string(to_bytes(component)); + if (utils::utf8::validate((const uint8_t *) key.data(), key.size())) { + out = fmt::format_to(out, "{}", key); + } else { + out = fmt::format_to(out, "{}", ""); + } } + return out; +} } // namespace detail template <>