diff --git a/common/include/ntstring.h b/common/include/ntstring.h index e9d66ea10..d4b06f5f5 100644 --- a/common/include/ntstring.h +++ b/common/include/ntstring.h @@ -11,48 +11,53 @@ class ntstring : public prohibit_void_ptr>, public array { + static char terminator() { return 0; } public: typedef array array_t; typedef char elements_t[L + 1]; using array_t::operator[]; typename array_t::reference operator[](int i) { return array_t::operator[](i); } typename array_t::reference operator[](unsigned i) { return array_t::operator[](i); } - bool _copy_n(std::size_t offset, const char *ib, std::size_t N) + __attribute_nonnull() + std::size_t _copy_n(std::size_t offset, const char *ib, std::size_t N) { + if (offset >= this->size()) + return 0; auto eb = ib; - bool r = (offset + N) <= L; + std::size_t r = (offset + N) <= L ? N : 0; if (r) eb += N; auto ob = std::next(this->begin(), offset); auto oc = std::copy(ib, eb, ob); - std::fill(oc, this->end(), 0); + std::fill(oc, this->end(), terminator()); return r; } template - bool _copy(std::size_t offset, const char *i) + __attribute_nonnull() + std::size_t _copy(std::size_t offset, const char *i) { static_assert(N <= L, "string too long"); return _copy_n(offset, i, N); } template - bool copy_if(I &&i) + std::size_t copy_if(I &&i) { return copy_if(static_cast(0), static_cast(i)); } template - bool copy_if(I &&i, std::size_t N) + std::size_t copy_if(I &&i, std::size_t N) { return copy_if(static_cast(0), static_cast(i), N); } template - bool copy_if(std::size_t out_offset, I &&i) + std::size_t copy_if(std::size_t out_offset, I &&i) { return copy_if(out_offset, static_cast(i), this->size()); } template void copy_if(std::size_t, const ntstring &, std::size_t = 0) = delete; template - bool copy_if(std::size_t out_offset, const array &i, std::size_t n = N) + std::size_t copy_if(std::size_t out_offset, const array &i, std::size_t n = N) { #ifdef DXX_HAVE_BUILTIN_CONSTANT_P if (__builtin_constant_p(n > N) && n > N) @@ -61,20 +66,69 @@ public: return copy_if(out_offset, i.data(), n); } template - bool copy_if(std::size_t out_offset, const char (&i)[N]) + std::size_t copy_if(std::size_t out_offset, const char (&i)[N]) { static_assert(N <= L + 1, "string too long"); return copy_if(out_offset, i, N); } - bool copy_if(std::size_t offset, const char *i, std::size_t N) + __attribute_nonnull() + std::size_t copy_if(std::size_t offset, const char *i, std::size_t N) { const std::size_t d = #ifdef DXX_HAVE_BUILTIN_CONSTANT_P (__builtin_constant_p(i[N - 1]) && !i[N - 1]) ? N - 1 : #endif - std::distance(i, std::find(i, i + N, 0)); + std::distance(i, std::find(i, i + N, terminator())); return _copy_n(offset, i, d); } + __attribute_nonnull() + std::size_t _copy_out(const std::size_t src_offset, char *const dst_base, const std::size_t dst_offset, const std::size_t max_copy) const + { + char *const dst = dst_base + dst_offset; + if (L > max_copy || src_offset >= this->size()) + { + /* Some outputs might not fit or nothing to copy */ + *dst = terminator(); + return 1; + } + const auto ie = std::prev(this->end()); + const auto ib = std::next(this->begin(), src_offset); + auto ii = std::find(ib, ie, terminator()); + if (ii != ie) + /* Only copy null if string is short */ + ++ ii; + const std::size_t r = std::distance(ib, ii); + if (r > max_copy) + { + /* This output does not fit */ + *dst = terminator(); + return 1; + } + std::copy(ib, ii, dst); + return r; + } + __attribute_nonnull() + std::size_t copy_out(std::size_t src_offset, char *dst, std::size_t dst_offset, std::size_t dst_size) const + { + if (dst_size <= dst_offset) + return 0; + return _copy_out(src_offset, dst, dst_offset, dst_size - dst_offset); + } + __attribute_nonnull() + std::size_t copy_out(std::size_t src_offset, char *dst, std::size_t dst_size) const + { + return copy_out(src_offset, dst, 0, dst_size); + } + template + std::size_t copy_out(std::size_t src_offset, array &dst, std::size_t dst_offset) const + { + return copy_out(src_offset, dst.data(), dst_offset, N); + } + template + std::size_t copy_out(std::size_t src_offset, array &dst, std::size_t dst_offset) const + { + return copy_out(src_offset, reinterpret_cast(dst.data()), dst_offset, N); + } operator bool() const = delete; operator char *() const = delete; operator elements_t &() const = delete; diff --git a/similar/main/net_udp.cpp b/similar/main/net_udp.cpp index 31f99b22f..f09035f36 100644 --- a/similar/main/net_udp.cpp +++ b/similar/main/net_udp.cpp @@ -198,14 +198,13 @@ static bool operator!=(const _sockaddr &l, const _sockaddr &r) template static void copy_from_ntstring(uint8_t *const buf, uint_fast32_t &len, const ntstring &in) { - std::memcpy(&buf[exchange(len, len + N)], in.data(), N); + len += in.copy_out(0, reinterpret_cast(&buf[len]), N); } template static void copy_to_ntstring(const uint8_t *const buf, uint_fast32_t &len, ntstring &out) { - std::memcpy(out.data(), &buf[exchange(len, len + N)], N); - out.back() = 0; + len += out.copy_if(reinterpret_cast(&buf[len]), N); } static void net_udp_prepare_request_game_info(array &buf, int lite)