From 1e6b8f9178370f99ec5cbbdfe5c86ab67596616d Mon Sep 17 00:00:00 2001 From: Egor Date: Sun, 8 Feb 2026 03:17:59 +0200 Subject: [PATCH] map: fix rename UB --- src/map.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/map.hpp b/src/map.hpp index 939fb23..6ae8a39 100644 --- a/src/map.hpp +++ b/src/map.hpp @@ -247,17 +247,23 @@ public: struct clientmap : map_base2 { void rename(Client *v, const char *newk) { - if (remove(v)) { - auto pos = m.lower_bound(std::string_view(newk)) - m.begin(); - auto vec = std::move(m).extract(); - vec.insert(vec.begin() + pos, v); - // FIXME: this is actually UB. better do some const_casting and std::rotate - m.replace(std::move(vec)); - } + auto it1 = m.find(v); + if (it1 == m.end()) + return; + auto it2 = m.lower_bound(std::string_view(newk)); + // Have to to this with a const_cast on the underlying vector, instead + // of m.extract/m.replace, because it's UB to replace with an unsorted + // vector. This will be an actual problem in e.g. libcxx with hardening + // enabled, since they assert that the array is sorted. + Client **p = const_cast(&*it1); + Client **q = const_cast(&*it2); + if (p < q) + std::rotate(p, p+1, q); + else + std::rotate(q, p, p+1); } }; -struct channelmap : map_base2 { -}; +using channelmap = map_base2; struct stringset : map_base2 { template std::string get(const K& k) = delete; -- 2.56.0